从Effective Java Item 11(明智地覆盖克隆)中考虑以下内容:Josh Bloch正在解释clone()
合同的错误。
此合同存在许多问题。 “不”的规定 构造函数被称为“太强大了。一个表现良好的克隆方法可以调用构造函数 创建正在构建的克隆内部的对象。如果是这样的 final,clone甚至可以返回由构造函数创建的对象。
有人可以解释Josh Bloch在第一段中所说的“如果类是final
,clone
甚至可以返回由构造函数创建的对象。” final
在这里与clone()
有什么关系?
答案 0 :(得分:22)
这是因为clone()的典型实现如下所示:
public class MyClass implements Cloneable {
protected Object clone() {
MyClass cloned = (MyClass) super.clone();
// set additional clone properties here
}
}
通过这种方式,您可以继承超类中的克隆行为。这是广泛的 假设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是最终的,没有人可以扩展它,因此使用构造函数是安全的。
答案 1 :(得分:20)
如果一个类不是final,那么clone
必须返回调用它的派生类最多的类。这不适用于构造函数,因为clone
不知道要调用哪一个。如果一个类是final,那么它不能有任何子类,所以在克隆时调用它的构造函数没有危险。
答案 2 :(得分:6)
为了可克隆,类不必提供自己的clone
实现。它可以将其委托给它的可克隆超类。接下来是:clone
必须始终返回与调用它的实例相同的类的实例。如果调用显式构造函数,则无法在所描述的情况下实现。如果课程覆盖clone
是最终的,另一方面,这没关系。
答案 3 :(得分:2)
clone
的合同规定“按惯例,应通过调用super.clone
”获取返回的对象。如果您的类不是final并且您返回通过构造函数调用获得的内容,则从子类调用super.clone()
将不会返回预期的结果(首先,返回的对象的类型将不是子类的类型,因为本机clone()
方法将返回。)
答案 4 :(得分:1)
见Jorado答案。这是解释。另外克隆在最终字段中有问题,请参阅: http://en.wikipedia.org/wiki/Clone_%28Java_method%29#clone.28.29_and_final_fields
你还应该阅读Josh关于克隆的采访: http://www.artima.com/intv/bloch13.html