简体   繁体   English

Java - 实现数组的深层和浅层副本

[英]Java - Implement deep and shallow copy of an array

I am trying to understand the concept of shallow vs deep copy in Java. 我试图理解Java中浅层和深层复制的概念。 There is a lot of articles and Q&A about this subject, but whenever I try to implement these concepts in a real Java code, everything become unclear to me. 关于这个主题有很多文章和问答,但每当我尝试在真正的Java代码中实现这些概念时,我都不清楚一切。

One of the answers on which I base my understanding is in this link , where deep and shallow copying are explained via schemas. 我基于理解的答案之一就是在这个链接中 ,通过模式解释深度和浅层复制。

I will show you below my implementation for each case: 我会在每个案例的实施情况下向您展示:

  • Shallow copy: 浅拷贝:

I took for my example the method System.arraycopy() as I read in many articles that it performs a shallow copy (along with the clone method) 我在我的示例中使用了System.arraycopy()方法,因为我在许多文章中读到它执行浅拷贝(以及克隆方法)

public class Test {

    public static void main(String[] args) {
        NameValue[] instance1 = {
                new NameValue("name1", 1),
                new NameValue("name2", 2),
                new NameValue("name3", 3),
        };
        NameValue[] instance2 = new NameValue[instance1.length];

        // Print initial state
        System.out.println("Arrays before shallow copy:");
        System.out.println("Instance 1: " + Arrays.toString(instance1));
        System.out.println("Instance 2: " + Arrays.toString(instance2));

        // Perform shallow copy
        System.arraycopy(instance1, 0, instance2, 0, 3);

        // Change instance 1
        for (int i = 0; i < 3; i++) {
            instance1[i].change();
        }

        // Print final state
        System.out.println("Arrays after shallow copy:");
        System.out.println("Instance 1: " + Arrays.toString(instance1));
        System.out.println("Instance 2: " + Arrays.toString(instance2));
    }

    private static class NameValue {
        private String name;
        private int value;

        public NameValue(String name, int value) {
            super();
            this.name = name;
            this.value = value;
        }

        public void change() {
            this.name = this.name + "-bis";
            this.value = this.value + 1;
        }

        @Override
        public String toString() {
            return this.name + ": " + this.value;
        }
    }
}

The result of the execution of the main methods is as follows: 执行主要方法的结果如下:

Arrays before shallow copy:
Instance 1: [name1: 1, name2: 2, name3: 3]
Instance 2: [null, null, null]
Arrays after shallow copy:
Instance 1: [name1-bis: 2, name2-bis: 3, name3-bis: 4]
Instance 2: [name1-bis: 2, name2-bis: 3, name3-bis: 4]

this result is an accordance with the schema of the previous link: 此结果符合上一个链接的架构: 浅拷贝

  • Deep copy: 深拷贝:

I took for this example the method Arrays.copyOf() as I read in many articles that it performs a deep copy (along with the Arrays.copyOfRange method) 我在这个例子中使用了Arrays.copyOf()方法,因为我在许多文章中读到它执行深层复制(以及Arrays.copyOfRange方法)

public static void main(String[] args) {
    NameValue[] instance1 = {
            new NameValue("name1", 1),
            new NameValue("name2", 2),
            new NameValue("name3", 3),
    };
    NameValue[] instance2 = new NameValue[instance1.length];

    // Print initial state
    System.out.println("Arrays before deep copy:");
    System.out.println("Instance 1: " + Arrays.toString(instance1));
    System.out.println("Instance 2: " + Arrays.toString(instance2));

    // Perform deep copy
    instance2 = Arrays.copyOf(instance1, 3);

    // Change instance 1
    for (int i = 0; i < 3; i++) {
        instance2[i].change();
    }

    // Print final state
    System.out.println("Arrays after deep copy:");
    System.out.println("Instance 1: " + Arrays.toString(instance1));
    System.out.println("Instance 2: " + Arrays.toString(instance2));
}

which displays: 显示:

Arrays before deep copy:
Instance 1: [name1: 1, name2: 2, name3: 3]
Instance 2: [null, null, null]
Arrays after deep copy:
Instance 1: [name1-bis: 2, name2-bis: 3, name3-bis: 4]
Instance 2: [name1-bis: 2, name2-bis: 3, name3-bis: 4]

If we base the deep copy logic on the previous schema, this should be the result: 如果我们将深层复制逻辑基于先前的模式,那么结果应该是: 深拷贝

As you may notice, the result of the execution of the main method is different from the logic of the schema above. 您可能会注意到,main方法的执行结果与上面的模式逻辑不同。

Any explanation will be welcome. 任何解释都将受到欢迎。

I don't know where you read that copyOf() performs a deep copy, because that is just plain wrong. 我不知道你在哪里读到copyOf()执行深层复制,因为这是完全错误的。

Quoting javadoc of Arrays.copyOf(T[] original, int newLength) : 引用Arrays.copyOf(T[] original, int newLength) javadoc:

For all indices that are valid in both the original array and the copy, the two arrays will contain identical values . 对于在原始数组和副本中都有效的所有索引, 这两个数组将包含相同的值

That means it's a shallow copy. 这意味着它是一个浅薄的副本。 To be a deep copy, the values would have to point to different objects, since the referenced object would have to be a copy too. 要成为深层副本,值必须指向不同的对象,因为引用的对象也必须是副本。

To perform a deep copy, you have to iterate the array and copy the values. 要执行深层复制, 必须迭代数组并复制值。 Java can't do that for you, because it doesn't know how to copy the object. Java无法为您做到这一点,因为它不知道如何复制对象。

Eg how would Java know how to copy a NameValue object? 例如,Java如何知道如何复制NameValue对象? clone() ? clone() Copy constructor? 复制构造函数? Serialize+Deserialize? 序列化+反序列化? Factory method? 工厂方法? Other means? 其他方法?

I am trying to understand the concept of shallow vs deep copy in Java. 我试图理解Java中浅层和深层复制的概念。

In Java you pass around and store references to objects not the objects themselves. 在Java中,您传递并存储对象的引用而不是对象本身。
So when you have an NameValue[] array the array does not contain the objects NameValue but references to the objects. 因此,当您拥有NameValue[] array该数组不包含对象NameValue而是对对象的引用。
So when you do a shallow copy to NameValue[] array2 it means you are just copying the references from one array to the other. 因此,当您对NameValue[] array2执行浅复制时,这意味着您只是将引用从一个数组复制到另一个数组。 Which effectively means that now both array and array2 refer to exactly the same objects and any change you do from array[2] will be visible from array2[2] (same object). 这实际上意味着现在arrayarray2指向完全相同的对象,并且从array2[2] (同一个对象)可以看到从array[2]进行的任何更改。

When you deep copies you copy each object completely to another memory area and you keep a reference to that new object in your new array. 深度复制时,将每个对象完全复制到另一个内存区域,并在新阵列中保留对该新对象的引用。
This way the 2 arrays now refer to different objects and any change to array[2] are not visible from array2[2] 这样,2个数组现在引用不同的对象,并且从array2[2]看不到对array[2]任何更改

Update: 更新:
This does not apply to primitives that do store the actual value and not a reference. 这不适用于存储实际值而不是引用的基元。
So an int[] a when you copy you get a copy of the values (ie deep copy in a sense) because a[2] contains the value itself and not the reference to the value. 所以当你复制时你得到一个int[] a得到一个值的副本(即某种意义上的深拷贝),因为a[2]包含值本身而不是对值的引用。

I think there is a little missunderstanding that Arrays.copyOf() produces a deep copy. 我认为有一点误解, Arrays.copyOf()会生成一个深层副本。

Arrays.copyOf() makes a new array that contains old refrences to objects that are not being copied and as the link that I've added explains in the case of nested arrays they will not get copied and hence it can't be considered a deep copy but a shallow copy. Arrays.copyOf()创建一个新数组,其中包含对未被复制的对象的旧Arrays.copyOf() ,并且我添加的链接在嵌套数组的情况下解释它们不会被复制,因此它不能被视为拷贝,但浅拷贝。

See this for more information. 有关更多信息,请参阅

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM