Effective Java:分析clone()方法

请考虑以下有效Java项目11(明智地覆盖克隆),其中Josh Bloch解释了clone()合同的错误。

这份合同存在许多问题。 “没有被称为构造函数”的规定过于强大。 一个行为良好的克隆方法可以调用构造函数来创建正在构建的克隆内部的对象。 如果类是final,clone甚至可以返回由构造函数创建的对象。

有人可以解释Josh Bloch在第一段中所说的“如果类是final ,则clone甚至可以返回由构造函数创建的对象”。 finalclone()有什么关系?

如果一个类不是final,则clone必须返回调用它的派生类最多的类。 这不适用于构造函数,因为clone不知道要调用哪一个。 如果一个类是final,那么它不能有任何子类,所以在克隆时调用它的构造函数没有危险。

这是因为clone()的典型实现如下所示:

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

通过这种方式,您可以inheritance超类中的克隆行为。 人们普遍认为clone()操作的结果将根据调用它的对象返回正确的实例类型。 IE浏览器。 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是最终的,没有人可以扩展它,因此使用构造函数是安全的。

类不必提供自己的clone实现以便可clone 。 它可以将其委托给它的可克隆超类。 接下来是: clone必须始终返回与调用它的实例相同的类的实例。 如果调用显式构造函数,则无法在所描述的情况下实现。 如果类overridng clone是final,另一方面,这没关系。

clone的契约指定“按照惯例,返回的对象应该通过调用super.clone获得”。 如果你的类不是final并且你返回通过构造函数调用获得的东西,从子类调用super.clone()将不会返回预期的结果(首先,返回的对象的类型将不是子类的类型,因为native clone()方法会返回)。

见Jorado答案。 这是解释。 另外克隆在最终字段中有问题,请参阅: http : //en.wikipedia.org/wiki/Clone_%28Java_method%29#clone.28.29_and_final_fields

您还应该阅读Josh关于克隆的访谈: http : //www.artima.com/intv/bloch13.html