【问题标题】:Is clone() in java shallow copy?java中的clone()是浅拷贝吗?
【发布时间】:2011-07-13 20:23:33
【问题描述】:

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

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

我从wikipedia 读到这篇文章。

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

【问题讨论】:

标签: java deep-copy shallow-copy


【解决方案1】:

默认的Object.clone()确实是浅拷贝。但是,除非您的对象实现 Cloneable,否则它的设计目的是抛出 CloneNotSupportedException

当您实现Cloneable 时,您应该覆盖clone() 以使其进行深层复制,方法是在所有本身可克隆的字段上调用clone()

【讨论】:

  • 使克隆深或浅不是“应该”或“不应该”的事情,它完全取决于预期的用途。
  • @jtahlborn:这确实是一个“应该”的事情,因为其他打电话给你clone 的人会期待所描述的行为。当然,也有例外,例如通用容器(@jt 的回答)。但总的来说,这就是预期。
  • 实际上,考虑到所有容器都使用浅克隆,为什么你会声称深度是期望? (容器是 jdk 中唯一可以克隆的可变类,我能想到)。
  • 对于深拷贝,您可以序列化对象(在内存中)并反序列化为新对象。这将是一个精确的克隆(深拷贝)
【解决方案2】:

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

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

class B { }

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

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

firstA 和 secondA 中的 B 实例将是相同的。您将没有 B 实例的副本。这就是为什么说 clone() 是做浅拷贝的原因。

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

【讨论】:

    【解决方案3】:

    顺便说一句,我很惊讶没有人提到Joshua Bloch's views on Cloneable

    如果您已阅读有关克隆的项目 在我的书中,尤其是如果你阅读 字里行间,你会知道 我认为克隆被深深地破坏了。那里 是一些设计缺陷,最大的 也就是 Cloneable 接口 没有克隆方法。然后 意味着它根本不起作用:制作 Cloneable 没有说的东西 关于你能做什么的任何事情 它。相反,它说的是 它可以在内部做什么。它说 如果通过调用 super.clone 反复它最终调用对象的 clone方法,这个方法会返回 原件的现场副本。

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

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

        【讨论】:

          【解决方案6】:

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

          隐式地,随着类型上复杂、可变字段数量的增加,克隆的价值会减少。

          【讨论】:

            【解决方案7】:

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

            【讨论】:

              【解决方案8】:

              是的。

              但首先你需要你的类实现 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);
                  }
              }
              

              输出:真

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2010-11-13
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多