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

我试图理解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; } } } 

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

 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] 

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

  • 深拷贝:

我在这个例子中使用了方法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)); } 

显示:

 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方法的执行结果与上面的模式逻辑不同。

任何解释都将受到欢迎。

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

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

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

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

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

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

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

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

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

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

我认为有一点误解, Arrays.copyOf()会生成一个深层副本。

Arrays.copyOf()创建一个新数组,其中包含对未被复制的对象的旧Arrays.copyOf() ,并且我添加的链接在嵌套数组的情况下解释它们不会被复制,因此它不能被视为拷贝,但浅拷贝。

有关更多信息,请参阅此