System.arraycopy():使用基本类型和对象引用进行浅复制或深复制

4

我在某个地方读到,System.arraycopy 会为原始数据类型创建新的副本,并为对象引用创建浅层副本。

因此,我开始使用以下代码进行实验:

//trying with primitive values
int a[] ={1,2,3};
int b[] = new int[a.length];
System.arraycopy(a,0,b,0,a.length);
b[0] = 9;
System.out.println(Arrays.toString(a));
System.out.println(Arrays.toString(b));
//now trying with object references
Object[] obj1 = {new Integer(3),new StringBuffer("hello")};
Object[] obj2 = new Object[obj1.length];
System.arraycopy(obj1,0,obj2,0,obj1.length);
obj1[1] = new StringBuffer("world");
System.out.println(Arrays.toString(obj1));
System.out.println(Arrays.toString(obj2));

并且输出结果是:
[1, 2, 3]
[9, 2, 3]
[3, world]
[3, hello]

但是我的期望是
[1, 2, 3]
[9, 2, 3]
[3, world]
[3, world]

从上面的代码中,我了解到System.arraycopy为对象引用执行深拷贝。 如果是这样,那么为什么obj1[0] == obj2[0] 返回 true

"基本类型的深拷贝". 当定义中它们并不引用任何更深层次的东西时,如何对基本类型进行深拷贝? - RealSkeptic
4个回答

5
你有一个错误的观念。
一旦你完成

obj1[1] = new StringBuffer("world");

您已经在obj1[1]替换了引用。现在这两个数组包含对不同对象的不同引用。

如果要查看复制的是实际引用,请尝试以下操作:

obj1[1].setLength(3);

现在,obj1[1]obj2[1]都应该包含字符串hel,因为您没有替换引用,而是改变了内容

4
System.arraycopy执行浅复制,这意味着当应用于非原始数组时,它会复制Object引用。因此,在执行System.arraycopy(obj1,0,obj2,0,obj1.length);后,obj1[0]==obj2[0]obj1[1]==obj2[1],因为两个数组都持有对相同Object的引用。一旦您为obj1[1]分配了新值,obj1[1]不再指向与obj2[1]相同的StringBuffer实例。这就是为什么Arrays.toString(obj1)Arrays.toString(obj2)的输出结果不同的原因。如果...(后面的文本缺失)
obj1[1] = new StringBuffer("world");

你需要编写的是

obj1[1].setLength(0);
obj1[1].append("world");

两个打印语句都会输出[3, world],因为两个数组仍然引用同一个StringBuffer实例。


1
不,这是引用的浅拷贝。
首先,您创建对`new StringBuffer("hello")`的引用,然后对其进行浅拷贝。因此,您有一个`StringBuffer`,但有两个对它的引用。
最后,您将另一个引用替换为完全的`new StringBuffer("world")`。

如果是这样,obj1 == obj2 应该返回 true,对吧?但实际上它返回了 false - gajapathy p
不,它们不是指向同一个数组的引用,所以当然返回false。 - Kayaman

0
我了解到System.arraycopy对于对象引用进行深度复制。如果是这样,为什么obj1 [0] == obj2 [0]会返回true?
不,你错了,它不执行深度复制。因为obj1 [0] == obj2 [0]引用相同的整数对象(即存储在数组中索引“0”处的引用),所以你得到的答案是true。此外,您可以比较obj1 [1] == obj2 [1],它返回false,因为两个StringBuffer引用是不同的。
另外,另一个要点是System.arrayCopy只进行浅层复制(仅从一个数组复制引用/值到另一个数组),您可以参考here

obj1[0] == obj2[0]比较的是整数值,但实际上这是错误的。obj1[0]obj2[0]由于arraycopy语句的结果而引用了同一个Integer对象,因此obj1[0] == obj2[0]才成立。如果在arraycopy语句之后添加obj2[0] = new Integer(3);,那么即使两个对象仍然具有相同的值(3),obj1[0] == obj2[0]也不再成立。 - Eran

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接