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

Str*_*der 8 java arrays deep-copy shallow-copy

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

我基于理解的答案之一就是在这个链接中,通过模式解释深度和浅层复制.

我会在每个案例的实施情况下向您展示:

  • 浅拷贝:

我在我的示例中使用了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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

执行主要方法的结果如下:

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]
Run Code Online (Sandbox Code Playgroud)

此结果符合上一个链接的架构: 浅拷贝

  • 深拷贝:

我在这个例子中使用了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));
}
Run Code Online (Sandbox Code Playgroud)

显示:

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]
Run Code Online (Sandbox Code Playgroud)

如果我们将深层复制逻辑基于先前的模式,那么结果应该是: 深拷贝

您可能会注意到,main方法的执行结果与上面的模式逻辑不同.

任何解释都将受到欢迎.

And*_*eas 5

我不知道你在哪里阅读copyOf()执行深层复制,因为这是完全错误的.

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

对于在原始数组和副本中都有效的所有索引,这两个数组将包含相同的值.

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

要执行深层复制,必须迭代数组并复制值.Java无法为您做到这一点,因为它不知道如何复制对象.

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

  • @Andreas @ g0dkar我从作者Richard M. Reese的书"_Oracle Certified Associate,Java SE 7 Programmer Study Guide_"中获得了这些信息.在第4章_Copying Arrays_部分的摘要中,评论说**使用`Arrays.copyOf`方法执行整个数组的深层复制**...根据这些信息我的逻辑我没有去远远寻找'Arrays.copyOf`方法的实现 (4认同)

Jim*_*Jim 4

我试图理解 Java 中浅复制与深复制的概念。

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

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

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