Java中的clone()方法是浅拷贝吗?

17

clone()方法是Java中用于复制对象的方法,它创建了一个与已存在对象相同类的新实例,并将所有字段复制到这个新实例中(即"浅拷贝")。此信息来自于维基百科

你可能会对为什么它是浅拷贝感到困惑。实际上,clone()方法确实会创建一个新实例并复制所有字段,但是如果这些字段本身是对象,则只会复制引用而不是对象本身。因此,在新实例中,这些引用指向的对象与原始对象中的引用指向的对象相同。这就是clone()方法所做的全部,所以它被称为浅拷贝而不是深拷贝。希望解决你的疑问。


除了这个之外,还有许多其他的副本,https://dev59.com/9XM_5IYBdhLWcg3w43pt - mindas
8个回答

22

默认的Object.clone()确实是浅拷贝。然而,它的设计是除非您的对象实现了Cloneable,否则会抛出CloneNotSupportedException异常。

当您实现Cloneable时,您应该重写clone()以使其执行深拷贝,并调用所有可克隆字段上的clone()方法。


7
将克隆对象设为深克隆或浅克隆并没有“应该”或“不应该”的标准,这完全取决于预期的使用方式。 - jtahlborn
3
@jtahlborn说:确实,这是一个“应该”做的事情,因为调用你的clone方法的其他人会期望它像描述的那样行为。当然,也有例外情况,比如对于通用容器(@jt's答案)。但总的来说,这是期望的行为。 - C. K. Young
2
实际上,考虑到所有容器都使用浅克隆,为什么你会认为深克隆是期望的呢?(容器是我能想到的 JDK 中唯一可克隆的可变类)。 - jtahlborn
2
对于深拷贝,您可以将对象(在内存中)序列化并反序列化为一个新对象。这将是一个完全相同的克隆(深拷贝)。 - SnakeDoc

8

这是一个浅拷贝,因为它只复制了对其他对象的引用。假设我们有以下类:

class A {
    B variable
    A() {
        variable = new B();
    }
}

class B { }

现在我们来克隆一个A类实例:

A firstA = new A();
A secondA = firstA.clone();

firstA和secondA中的B实例将是相同的。您不会有B实例的副本。这就是为什么clone()被称为浅复制的原因。

您链接页面上的图表应该帮助您理解所有内容。


5

顺便提一下,我很惊讶没有人提到 Joshua Bloch关于Cloneable的观点

如果你读过我的书中关于克隆的部分,特别是在字里行间,你会知道我认为clone方法是有严重缺陷的。存在一些设计上的缺陷,其中最大的问题是Cloneable接口没有clone方法。这意味着它根本无法正常工作:将某物设置为可克隆并不能说明你能够对它进行什么操作。相反,它只是说明了它在内部可以做什么。它表示,如果通过反复调用super.clone最终调用Object的clone方法,那么这个方法将返回原始对象的一个字段副本。


4

clone()创建所有字段的副本。Java有原始类型和引用 - 当您克隆对象时,您会得到一个新对象,其中包含所有基本字段的副本(就像深层复制),但还会复制所有引用字段。因此,结果是您获得两个对象,它们拥有自己的原语副本和对相同对象的引用副本 - 原始对象和复制对象都将使用相同的对象。


3

有些对象不提供深复制。例如,ArrayList会克隆列表,但不会克隆列表中的元素。以下内容来自JavaDoc关于ArrayList的文档:

public Object clone()

    Returns a shallow copy of this ArrayList instance. (The elements themselves are not copied.)

2

Object.clone()的默认实现是浅拷贝。对于具有大量基本字段或不可变字段的类型,此行为仍然很有用。您可以查看如何正确重写克隆方法?以了解如何正确地覆盖它。在调用super.clone()后,然后将结果对象转换,您可以根据需要进行更深层次的克隆。

随着类型上复杂、可变字段数量的增加,克隆的价值会逐渐降低。


1

clone 的作用是由选择支持 clone 的每个对象定义的。Object.clone 是受保护的,因此除非有人明确定义了它,否则没有对象允许 clone。


0

是的。

但首先你需要让你的类实现Cloneable并抛出异常。

class A implements Cloneable{
    public int y;
    public B b;

    public A(){
        b = new B();
    }

    public static void main(String[] args) throws CloneNotSupportedException{
        A a = new A();
        A a2 = (A) a.clone();
        System.out.print(a.b==a2.b);
    }
}

输出:真


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