Java深克隆和浅克隆



我认为下面的clone方法是深度克隆,因为它在复制信息之前创建了一个新对象。然而,这是一个肤浅的克隆。我想知道为什么。

class FixedVector {
public static int count;
private Object data[];
private int length = 0;
public FixedVector(int size) {
count++;
data = new Object[size];
}
public void add(Object ob) {
if (length < data.length) {
data[length++] = ob;
} else {
throw new InsufficientSpaceException();
}
}
public Object get(int index) {
if (index < length) {
return data[index];
} else {
throw new IndexOutOfBoundsException();
}
}
public Object clone() {
FixedVector c = new FixedVector(data.length);
for (int i = 0; i < length; ++i) {
c.data[i] = data[i];
}
return c;
}
public static void main(String argv[]) {
FixedVector n = new FixedVector(10);
try {
n.get(1);
} catch (InsufficientSpaceException ie) {
System.out.println("ERROR 1");
} catch (IndexOutOfBoundsException oe) {
System.out.println("ERROR 2");
}
}
}

clone()方法是您实现的任何1。如果你想实现深度复制,那是允许的。如果你想实现浅拷贝,这也是允许的。

在这个例子中,FixedVector的作者显式地clone()实现为浅拷贝。显然,代码将按照编写的方式运行……即浅层复制data数组。

现在…如果你问在这种情况下会发生什么:

public class FixedVector implements Cloneable {
...

public Object clone() {
return super.clone();
}
}

更有趣。这里我们依靠的是"魔法"。Object.clone()的克隆行为。但是它被定义为执行目标对象字段的浅拷贝。因此克隆将与克隆对象共享数据数组。(这不是我们想要的,在这种情况下,因此FixedVector实现克隆,正如你的问题。)


注意"deep"one_answers";shallow"副本很有弹性。在您的示例中,实际上(至少)有3种方法可以执行复制:

  • Object.clone()方式给出了一个共享的data数组。那是"肤浅的"。副本。

  • 问题中的方法给出了不同的data数组,但共享元素。这是一个"深"字。副本。

  • 另一种方法是克隆数组中的元素。这将是一个"更深"的问题。副本。在您的示例中,如果可以更改

    c.data[i] = data[i];
    

    c.data[i] = data[i].clone();
    

    但实际深度取决于元素类2如何实现clone。这个行为是类特有的。


1 -Object.clone()javadoc谈论"一般意图";clone()方法,但它明确表示允许类忽略它。然而,我想说忽略javadoc所说的内容是不明智的。
2 -这不会按原样编译。但是,如果您将Object[] data替换为SomeClass[] data,其中SomeClassclone()声明为public方法,则可以。