有效的 Java:分析 clone() 方法

2022-09-02 11:27:37

考虑以下来自 Effective Java Item 11(明智地覆盖克隆)中的以下内容,其中 Josh Bloch 正在解释合同出了什么问题。clone()

此合同存在许多问题。“不调用构造函数”的规定过于强烈。行为良好的克隆方法可以调用构造函数来创建正在构造的克隆内部的对象。如果该类是最终类,则 clone 甚至可以返回由构造函数创建的对象。

有人可以解释Josh Bloch在第一段中所说的话吗:“如果类是,甚至可以返回由构造函数创建的对象。这与这里有什么关系?finalclonefinalclone()


答案 1

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

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

通过这种方式,您可以从超类继承克隆行为。人们普遍认为,clone() 操作的结果将根据调用它的对象返回正确的实例类型。韦普this.getClass()

因此,如果一个类是最终的,你不必担心子类调用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 是最终的,则没有人可以扩展它,因此使用构造函数是安全的。


答案 2

如果某个类不是最终的,则必须返回为其调用它的最派生的类。这不能与构造函数一起使用,因为不知道要调用哪一个。如果一个类是最终的,它不能有任何子类,所以在克隆时调用它的构造函数没有危险。cloneclone