Java中的clone()方法如何使用浅拷贝?

3

我知道这个问题可能已经被问过了,但我的问题有点不同。我已经搜索过了,知道了Java方法object.clone()使用浅拷贝,也就是复制引用而非实际对象。假设我有一个dog类。

 Class Dog{
     public Dog(String name, DogTail tail, DogEar ear){
          this.name = name;
          this.tail = tail;
          this.ear  = ear;   
     } 
} 
DogTail t = new DogTail(); 
DogEar ear = new DogEar(); 
Dog dog1 = new Dog("good", t,ear);

假设我想要获得dog1的一个副本。

Dog dognew = dog1.clone();

如果这个clone()方法使用浅拷贝,那么它将会复制引用。因此,如果我在上面创建的对象或者ear方法中进行更改,那么dognew对象也会发生变化,反之亦然。那么这种克隆有什么好处呢?这个问题是由于有人说创建一个巨大的对象比克隆更糟糕,因为你可以在使用clone()方法时节省性能。


如果你克隆它并修改克隆体,当你打印原始对象时,你能看到修改吗?这是找出发生了什么的好开始。 - apxcode
1
很多时候,浅拷贝正是你想要的。这是clone()方法的合理默认行为。如果这不适用于您的应用程序,请自己编写一个复制构造函数或deepCopy()方法。 - Ted Hopp
只需记住不要使用clone()Cloneable接口。作为学术兴趣的主题-很棒。 - RealSkeptic
2个回答

1

clone()方法的默认版本会创建对象的浅拷贝。

对象的浅拷贝将精确复制原始对象的所有字段。如果原始对象具有对其他对象的引用作为字段,则仅会将这些对象的引用复制到克隆对象中,不会创建这些对象的副本。这意味着通过克隆对象对这些对象所做的任何更改都将反映在原始对象或反之亦然。

要创建对象的深层副本,您可以重写clone()方法。

protected Object clone() throws CloneNotSupportedException
{
    DogTail tail = (DogTail) this.tail.clone();

    Dog dog = (Dog) super.clone();

    dog.tail = tail;

    return dog;
}

@TedHopp 说得好。我用“可能”代替了“有”。你提出了一个有效的观点,即有多种方法可以解决问题。 - apxcode
clone() 的默认版本也是 protected 的,因此除非你覆盖它,否则你实际上不能使用它(在子类/包之外)。这是不使用它的一个很好的理由... 人们往往会忘记它,因为在 Java 标准集合等中已经被公共方法覆盖了。 - RealSkeptic

1

"所以,如果我改变上面创建的t对象或ear方法,它会在dognew对象中发生变化,反之亦然。"

这取决于你所说的"改变"的含义:

如果你指的是改变t引用的DogTail实例的状态,例如t.setSomething(someValue);,那么是的。它是同一个实例,不管谁导致了改变或者改变发生在哪里。

但是,如果你指的是改变克隆中t所引用的内容,例如t = new DogTail();,原始版本中的t将不会受到影响。在此之后,克隆和原始版本中的t将引用不同的实例。


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