13

clone()在java中是浅拷贝吗?

最终这会到达 Object(最上层类)的 clone() 方法,该方法创建一个与对象相同的类的新实例,并将所有字段复制到新实例(“浅拷贝”)。

我从维基百科读到这个。

我不明白为什么它是浅拷贝。clone()将创建一个包含所有字段的新实例。这只是一个深拷贝吗?使困惑。需要给我一些解释。

4

8 回答 8

22

默认Object.clone()确实是浅拷贝。但是,它旨在抛出 a CloneNotSupportedException,除非您的对象实现Cloneable.

并且当您实现 时Cloneable,您应该通过调用所有本身可克隆的字段来覆盖clone()以使其进行深层复制。clone()

于 2011-03-11T23:00:15.643 回答
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() 做浅拷贝的原因。

您链接的页面上的图表应该可以帮助您理解所有这些。

于 2011-03-11T23:08:31.733 回答
5

顺便说一句,我很惊讶没有人提到Joshua Bloch 对 Cloneable 的看法

如果你读过我书中关于克隆的项目,尤其是如果你读到字里行间,你就会知道我认为克隆被严重破坏了。有一些设计缺陷,其中最大的一个是 Cloneable 接口没有克隆方法。这意味着它根本不起作用:制作可克隆的东西并没有说明你可以用它做什么。相反,它说明了它可以在内部做什么。它表示如果通过重复调用 super.clone 最终调用 Object 的 clone 方法,该方法将返回原始的字段副本。

于 2011-03-11T23:53:22.977 回答
4

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

于 2011-03-11T23:03:56.360 回答
3

有些对象不提供深拷贝。例如,ArrayList 将克隆列表,但不会克隆列表中的元素。以下来自 ArrayList 的JavaDoc

public Object clone()

    Returns a shallow copy of this ArrayList instance. (The elements themselves are not copied.)
于 2011-03-11T23:02:51.517 回答
2

Object.clone() 的默认实现是浅拷贝。此行为对于具有大量原始字段或不可变字段的类型仍然有用。您可以查看如何正确覆盖克隆方法?如何正确覆盖它。在调用 super.clone(),然后转换生成的对象后,您可以根据需要进行更深的克隆。

隐含地,随着类型上复杂、可变字段数量的增加,clone 的值会减小。

于 2011-03-11T23:10:21.570 回答
1

clone为选择支持克隆的每个对象定义了什么。Object.clone 是受保护的,因此除非有人明确定义,否则任何对象都不允许克隆。

于 2011-03-11T23:00:20.337 回答
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);
    }
}

输出:真

于 2011-03-11T23:08:33.370 回答