Java - 实现数组的深拷贝和浅拷贝

Java - Implement deep and shallow copy of an array

我正在尝试理解 Java 中浅拷贝与深拷贝的概念。 有很多关于这个主题的文章和问答,但每当我尝试在真实的 Java 代码中实现这些概念时,一切都变得不清楚。

我的理解所依据的答案之一是 this link,其中通过模式解释了深度和浅层复制。

我将在下面展示我对每个案例的实施:

我以方法 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;
        }
    }
}

主要方法执行结果如下:

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]

此结果与之前的架构一致link:

我在这个例子中采用了 Arrays.copyOf() 方法,因为我在许多文章中读到它执行深度复制(以及 Arrays.copyOf范围方法)

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));
}

其中显示:

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]

如果我们将深度复制逻辑基于之前的模式,结果应该是这样的:

你可能注意到了,main方法的执行结果和上面schema的逻辑不一样。

欢迎任何解释。

我不知道你在哪里读到 copyOf() 执行深拷贝,因为那完全是错误的。

引用 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.

这意味着它是一个浅拷贝。要成为深拷贝,值必须指向不同的对象,因为引用的对象也必须是一个副本。

要执行深层复制, 必须迭代数组并复制值。 Java 不能为你做那件事,因为它不知道如何复制对象。

例如Java 怎么知道如何复制 NameValue 对象? clone()?复制构造函数?序列化+反序列化?工厂方法?其他方式?

I am trying to understand the concept of shallow vs deep copy in Java.

在 Java 中,您传递并存储对对象的引用而不是对象本身。
因此,当您有一个 NameValue[] array 时,该数组不包含对象 NameValue 但包含对对象的引用。
因此,当您对 NameValue[] array2 进行浅拷贝时,这意味着您只是将引用从一个数组复制到另一个数组。这实际上意味着现在 arrayarray2 指的是完全相同的对象,并且您对 array[2] 所做的任何更改都将在 array2[2](同一对象)中可见。

当你深拷贝时,你将每个对象完全复制到另一个内存区域,并在你的新数组中保留对该新对象的引用。
这样 2 个数组现在引用不同的对象并且对 array[2] 的任何更改在 array2[2]

中不可见

更新:
这不适用于存储实际值而不是引用的原语。
因此,当您复制 int[] a 时,您会得到值的副本(即某种意义上的深拷贝),因为 a[2] 包含值本身而不是对值的引用。

我认为 Arrays.copyOf() 产生了深拷贝,我认为有一点误解。

Arrays.copyOf() 创建一个新数组,其中包含对未被复制的对象的旧引用,正如我添加的 link 在嵌套数组的情况下解释的那样,它们将不会被复制因此它不能被认为是一个拷贝而是一个浅拷贝。

有关详细信息,请参阅 this