Java的clone()方法

4

我读过J.Bloch的《Effective Java》一书,其中提到:

如果你设计一个用于继承的类,请注意如果你选择不提供良好的受保护的 clone 方法,那么子类将无法实现 Cloneable 接口。

我有一个名为 A 的类:

public class A{}

类B继承自类A:

public class B extends A implements Cloneable {

}

所以在这种情况下我不能覆盖clone()方法吗?如果是的话,请解释为什么。


使用复制构造函数。 - Everv0id
过去,我曾经有一个客户需要自定义shallowClone()deepClone()方法,以避免Java中的clone()混乱。他们希望完全控制这些方法。对我来说很有道理。 - user4229245
@tgm1024,那么在实际生活中,在所有情况下使用clone()方法都是一个坏主意吗? - Vladyslav Sheruda
@JamesSchermann,虽然有些人可能会这么说,但我只能说这是一种奇怪的范式,大多数人认为它已经过时了。我以前用过它,但它被认为存在问题,我更喜欢通过实现自己的复制来获得控制权。你可能会喜欢这个关于这个主题的有趣采访,采访对象是你读过的《Effective Java》的作者Josh Bloch。但在我的客户案例中,他们需要具有特定要求的深度和浅层复制功能。 - user4229245
Bloch的说法明显是错误的。也许他在其他上下文中谈论的是深拷贝,但是引用的这句话是完全错误的。 - user207421
显示剩余2条评论
3个回答

2
在您的情况下,您可以重写clone()方法:
public class A {
}

public class B extends A implements Cloneable {

    @Override
    public B clone() throws CloneNotSupportedException {
        return (B) super.clone();
    }
}

并且仍然具有有效的克隆机制 - 因此当您声明 implements Cloneable 时,您正在说真话。

然而,只需要给 A 添加一个 private 变量就可以打破这个承诺。

public class A {
    private int a;
}

现在你的承诺被打破了 - 除非A实现clone,否则你可以使用super.clone()

public class A {

    private int a;

    @Override
    public A clone() throws CloneNotSupportedException {
        A newA = (A) super.clone();
        newA.a = a;
        return newA;
    }
}

public class B extends A implements Cloneable {

    private int b;

    @Override
    public B clone() throws CloneNotSupportedException {
        B newB = (B) super.clone();
        newB.b = b;
        return newB;
    }
}

基本上 - 正如Joshua Bloch所说的那样 - 如果您不实现clone,您的子类也通常无法实现。


1
这是完全不正确的。A中的私有字段将被Object.clone()克隆。 - user207421

1

Cloneableclone() 已经被淘汰了,所以无论如何也不重要。然而,由于 clone() 总是应该调用 super.clone(),如果一个超类错误地实现了它,子类也无法修复它。

这与无法覆盖 clone() 没有任何关系,只是不会得到正确的实现。


1
你第一条语句(Cloneable已被弃用)确切是从哪里得来的? - Dominik Sandjaja
1
有很多关于它的讨论,这里是一个地方。实际上,Cloneable并没有被弃用,而是有缺陷的 - Kayaman
1
嗯,我完全同意“已过时”的部分。我只是觉得我可能错过了废弃部分。 - Dominik Sandjaja
@EJP,我认为我在这里的想法是,如果A不调用super.clone()(即Object.clone()),那么由于B也无法调用它,这将导致实现不正确。然而,似乎文档说明了“按照惯例,应通过调用super.clone()来获取返回的对象”,因此我想这只会导致一个非常规的实现。 - Kayaman
在我看来,Bloch所引用的那句话就是错误的。也许有一些上下文可以说明它。我没有这本书的副本,而我看到的摘录并没有给我留下深刻印象。 - user207421
我研究了一下。引用的这句话是整个部分的最后一句话,它既没有论据也没有例证支持,除非整个部分的目的就是要证明它,但实际上并没有这样做。 - user207421

0
当然你可以实现 B.clone()
J. Bloch 所提到的问题是(如果我没记错的话),如果没有一个好的 A.clone() 方法,那么 A 中的私有字段在 B 中就无法被正确地克隆。以下是一个简单的例子:
public class A {
  private String myText;
  public A (String myText) {
    this.myText = myText;
  }
  public String getExtendedText() {
    return "Hello something " + myText;
  }
}

public class B extends A implements Cloneable {
    private int someValue;
    // getter/setter

    public clone() {
        // how can you now provide a good clone with A.myText being cloned?
    }    
}

Object.clone() 会自动克隆 A.myTextB.someValue。在这种情况下,B.clone() 不需要做任何事情,只需调用 super.clone() 即可。 - user207421

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