19

JoshBlochがclone()コントラクトの何が問題になっているのかを説明しているEffectiveJavaItem 11(クローンを慎重にオーバーライドする)の次のことを考慮してください。

この契約には多くの問題があります。「コンストラクターが呼び出されない」という規定は強すぎます。正常に動作するクローンメソッドは、コンストラクターを呼び出して、構築中のクローンの内部にオブジェクトを作成できます。クラスがfinalの場合、cloneはコンストラクターによって作成されたオブジェクトを返すこともできます。

Josh Blochが最初の段落で言っていることを誰かが「クラスがの場合、コンストラクターによって作成されたオブジェクトを返すことさえできる」と説明できますfinalclone?こことは何の関係finalがありclone()ますか?

4

5 に答える 5

22

これは、 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 の場合、誰もそれを拡張できないため、コンストラクターを使用しても安全です。

于 2012-07-18T12:09:39.427 に答える
21

クラスが final でない場合、clone呼び出された最も派生したクラスを返す必要があります。cloneどちらを呼び出すかわからないため、コンストラクターでは機能しません。クラスが final の場合、サブクラスを持つことはできないため、クローン作成時にコンストラクターを呼び出しても危険はありません。

于 2012-07-18T12:06:58.873 に答える
7

クラスは、複製可能にするために独自の実装を提供する必要はありませんclone。それをクローン可能なスーパークラスに委任できます。ここに問題がありcloneます。呼び出されたインスタンスと同じクラスのインスタンスを常に返さなければなりません。明示的なコンストラクターが呼び出された場合、説明されているケースでこれを達成することは不可能です。一方、クラスのオーバーライドcloneが最終的なものである場合は、これで問題ありません。

于 2012-07-18T12:09:03.880 に答える
2

の契約でcloneは、「慣例により、返されるオブジェクトは呼び出しによって取得する必要がある」と指定されていますsuper.clone。クラスが final ではなく、コンストラクター呼び出しで取得したものを返す場合super.clone()、サブクラスからの呼び出しは期待される結果を返しません (まず、返されるオブジェクトの型は、ネイティブclone()メソッドとしてサブクラスの型にはなりません)。戻ります)。

于 2012-07-18T12:06:57.690 に答える
2

Joradoの回答を参照してください。これが説明です。追加のクローンでは、最終フィールドに問題があります: http://en.wikipedia.org/wiki/Clone_%28Java_method%29#clone.28.29_and_final_fieldsを参照してください。

クローンに関する Josh のインタビューもお読みください: http://www.artima.com/intv/bloch13.html

于 2012-07-18T12:11:16.790 に答える