克隆多维数组

17
int[][] array = new int[][] {...}
int[][] clone = array.clone();

我天真地期望它能起作用。但它没有——它只克隆了第一维,如果我想要一个真正的克隆,我必须手动克隆另一维。注意:内容已被正确复制。但当我改变clone[0][1]时,它也反映在array[0][1]中。

虽然.clone()已知执行的是浅克隆,但int[][]看起来像是单个对象(至少在我们不知道它的内部实现时)。

为什么选择这种行为?int[][]难道不是引用一个数组对象,而不仅仅是数组的第一维吗?在哪些情况下只克隆第一维是期望的行为?

4个回答

8
为什么选择这种行为?
很可能是为了保持一致性。
正如你所说,int[][] 引用了一个数组对象。每个数组元素的内容恰好是另一个数组,但这只是一个细节。Java会完全克隆所有数组,并且由于元素可以是任何类型,它不能保证执行深层复制。
因此,数组的 clone() 方法执行浅层复制,因此只有第一维被克隆。
(总的来说,似乎没有单一的“最佳”或“明显”的答案来回答克隆是否意味着深层复制。开发人员想要的取决于应用程序如何使用每个字段,因此一种适合所有情况的方法自然会有局限性。)

3

这种行为的原因是因为没有真正的多维数组。

Java通过创建数组的数组来实现多个维度。也就是说:

int[][] is actually Array<Array<int>>

因此,克隆将只复制第一维。
如果你在尝试使用一个三维数组,你将需要克隆三次。

1
我实际上无法复制您提到的行为。我看到一些答案提到浅拷贝是问题的根本原因。如果我错了,请纠正我,浅拷贝只是指在克隆时不会复制一个对象,而是会得到一个引用的副本。可以在这里找到一个很好的解释 In Java, what is a shallow copy?
在这种情况下,浅拷贝只会确保在克隆数组中反映出原始数组中的更改,但不会阻止任何内容被复制。
int[][] array = new int[][] {{1,2,3},{4,5,6}, {7,8,9}};
int[][] clone = array.clone();

//Try this to see magic of shallow copy
//array[2][1]=11;

for(int i=0;i<array.length;i++)
    for(int j=0;j<array[i].length;j++)
        System.out.println("array["+i+"]["+j+"]"+array[i][j]);

for(int i=0;i<clone.length;i++)
    for(int j=0;j<clone[i].length;j++)
        System.out.println("clone["+i+"]["+j+"]"+clone[i][j]);

对我来说,克隆已经完美地完成了,也就是说两个数组具有相同的内容。我能想到的唯一原因是在克隆之后我们实际上修改了原始数组(浅复制就会发挥作用),导致克隆数组不显示某些信息。
顺便说一下,我使用的是Java 1.6,希望这不是问题。
编辑:如果我们只需要理解为什么会出现多维数组的浅复制而不是深复制,请看以下两个事实:
1. 在克隆时,对象总是被克隆为浅复制(对象引用的副本),只有原生类型才会得到真正的副本。在Java中,什么是浅复制? 2. 在Java中,数组实际上是一个对象。Java中的数组是一个对象吗? 现在将1和2结合起来,我们知道Java中的多维数组只是一个对象,它具有其他数组对象的引用。
类似于ArrayObj-> {ArrayObj,ArrayObj,ArrayObj};

由于我们在对象内部有其他对象(组合),根据Java克隆规则,我们应该得到浅拷贝。


我来澄清一下。克隆确实发生了,但它不是深层的。 - Bozho

1

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