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

我天真地期望这会奏效。但它没有——它只克隆了第一个维度,如果我想要一个真正的克隆,我必须手动去克隆另一个维度。注意:内容已正确复制。但是当我改变时clone[0][1],它反映在array[0][1]

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

为什么选择这种行为?不是int[][]引用数组对象,而不仅仅是数组的第一个维度?在什么情况下只克隆第一维所需的行为?

4

4 回答 4

8

为什么选择这种行为?

一致性,很可能。

正如你所说,int[][]引用一个数组对象。碰巧每个数组元素的内容都是另一个数组,但这只是一个细节。Java 以相同的方式克隆所有数组,并且由于元素可以是任何类型,因此不能保证执行深度复制。

因此clone()对于数组执行浅拷贝,因此只克隆第一个维度。

(一般来说,对于克隆意味着深拷贝还是浅拷贝的问题,似乎没有单一的“最佳”或“明显”答案。开发人员想要什么取决于应用程序如何使用每个字段,所以一刀切的方法自然会有局限性。)

于 2013-04-24T07:41:24.470 回答
3

演示此行为是因为不存在真正的多维数组。

Java通过制作数组的数组来实现多维。意思是:

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

因此,克隆只会复制第一个维度。

如果您尝试使用 3 维数组,则需要克隆三次。

于 2013-04-24T07:41:36.187 回答
1

我实际上无法复制您提到的行为。我可以看到一些答案提到浅拷贝是问题的根本原因。如果我错了,请纠正我,浅拷贝只是意味着在克隆时我们将获得引用的副本,而不是对象的副本。可以在这里找到一个很好的解释在 Java 中,什么是浅拷贝?

在这种情况下,浅拷贝只会确保原始数组中的更改会反映在克隆数组中,但不会阻止任何内容被复制。

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,我希望这不是问题。

编辑:如果我们只需要了解为什么它们是多维数组的浅拷贝而不是深拷贝。让我们看2个事实

  1. 克隆时,对象总是被克隆为浅拷贝(对象引用的副本),只有本机类型才能获得真正的副本。在 Java 中,什么是浅拷贝?
  2. java中的数组实际上是对象java中的数组是对象吗

现在结合1和2,我们知道Java中的多维数组只是一个对象,它具有其他数组对象的引用。

像 ArrayObj->{ArrayObj, ArrayObj, ArrayObj};

而且因为我们在对象(组合)中有对象,所以我们应该根据 Java 克隆规则获得浅拷贝。

于 2013-04-24T08:03:04.687 回答
1

clone方法是所谓的浅拷贝(参见方法上的另一个 stackoverflow 答案clone),这意味着所有元素都是通过引用复制的。

要获得您想要的(也称为深度克隆),您可以使用递归方式自己复制每个数组Arrays.copy,因此您找到的每个(子)数组都将获得深度克隆,或者在深度克隆上查看这个 stackoverflow 答案

快乐的黑客:-)

于 2013-04-24T07:43:55.910 回答