Effective Java: 分析 clone() 方法

19
考虑 Effective Java 第11条 (谨慎覆盖clone方法) 中的以下内容,Josh Bloch解释了clone()合同存在的问题。
引用如下:
“这个合同有许多问题。规定“不调用任何构造函数”太过严格。行为良好的clone方法可以调用构造函数,在正在克隆的对象内部创建对象。如果类是final的,clone甚至可以返回由构造函数创建的对象。”
请问 Josh Bloch 在第一段中的“如果类是final,clone可以甚至返回由构造函数创建的对象”,是什么意思?在这里 finalclone() 有什么关系吗?
5个回答

23

这是因为典型的clone()实现看起来像这样:

public class MyClass implements Cloneable {
  protected Object clone() {
    MyClass cloned = (MyClass) super.clone();
    // set additional clone properties here
  }
}

通过这种方式,您可以继承超类的克隆行为。广泛认为,clone()操作的结果将根据其调用的对象返回正确的实例类型。也就是说,使用this.getClass()。

因此,如果一个类是final的,您不必担心子类调用super.clone()时未能获取正确的对象类型。

public class A implements Cloneable {
    public Object clone() {
       return new A();
    }
}


public class B extends A {
    public Object clone() {
       B b = (B)super.clone(); // <== will throw ClassCastException
    }
}

但是,如果A是final的,就没有人可以扩展它,因此使用构造函数是安全的。


21

如果一个类不是final的,则clone必须返回调用它的最派生类。这在使用构造函数时行不通,因为clone不知道应该调用哪个构造函数。如果一个类是final的,它就不可能有任何子类,因此在克隆时调用其构造函数是没有危险的。


7

一个类不一定要提供自己的clone实现才能被克隆。它可以将这个任务委托给其可克隆的超类。但是有个问题:clone方法必须始终返回与调用它的实例相同的类的实例。如果调用了显式构造函数,则无法在所述情况下实现。另一方面,如果覆盖clone的类是final的,则这是可以的。


2

clone的协定规定:“按照惯例,返回的对象应该通过调用super.clone来获得”。如果您的类不是最终类,并且您返回使用构造函数调用获得的某些东西,则从子类调用super.clone()将不会返回预期的结果(首先,返回对象的类型不会是子类的类型,因为本机clone()方法会返回)。


2

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