効果的なJava。クローニング可能なインターフェース
-
11-12-2019 - |
質問
私は効果的なJava Bookを読み、クローニング可能なインターフェースを説明する1つの段落を理解していません。誰かがこの段落を説明することができます:
...プログラマは、それらがクラスを拡張して呼び出すと仮定している
super.clone
サブクラスから、返されたオブジェクトはインスタンスになります サブクラスの。スーパークラスがこれを提供できる唯一の方法 機能は、super.clone
を呼び出して取得したオブジェクトを返すことです。 クローンメソッドがコンストラクタによって作成されたオブジェクトを返す場合、それは 間違ったクラスを持っています。ありがとう。
解決
私はそれ自身のclone
で始まるべきであり、それ自体が壊れているので、Sheep(Sheep cloneMe)
のようなcopyコンストラクタはclone
よりもはるかに優雅な慣用句であることを考える。あなたは本を読んでいるので、あなたはおそらくこれを知っているのですが、ここに置く価値があります。
とにかく質問に答えるために:
Cloneable
は、呼び出されたオブジェクトと同じ型のオブジェクトを作成します。このため、結果を得る予定の結果を得るために、Object.clone()
まで「カスケード」に強く奨励されています。誰かがこの規約に従わないことを決定した場合、あなたは慣例を破ったクラスの種類のオブジェクトを終わらせるでしょう、それは多数の問題を引き起こすでしょう。
私はso のようなクラスを持っています
class Sheep implements Cloneable {
Sheep(String name)...
public Object clone() {
return new Sheep(this.name); // bad, doesn't cascade up to Object
}
}
class WoolySheep extends Sheep {
public Object clone() {
return super.clone();
}
}
.
突然、私がしたら
WoolySheep dolly = new WoolySheep("Dolly");
WoolySheep clone = (WoolySheep)(dolly.clone()); // error
.
Object
から戻ってきたものは、dolly.clone()
ではなくSheep
です。
他のヒント
私は@コルシカの答えに同意しません。Java5.0以来JavaはCovariant Return型をサポートしているため、clone()の正しい実装は次のとおりです。
class Sheep implements Cloneable {
Sheep(String name)...
public Sheep clone() {
return new Sheep(this.name);
}
}
class WoolySheep extends Sheep {
public WoolySheep clone() {
return super.clone(); // compile time error, Type miss match.
}
}
.
また、提案された代替コピーコンストラクタは多型を支持しない。次の例(Copy Constructorができません)を検討してください。
interface Animal implements Cloneable {
String whatAreYou()
}
class Cat implements Animal {
String whatAreYou() {
return "I am a cat";
}
Cat clone() {
return new Cat();
}
}
class Dog implements Animal{
String whatAreYou() {
return "I am a dog";
}
Dog clone() {
return new Dog();
}
}
class Lib {
Animal cloneAnimal(Animal animal) {
return animal.clone();
}
}
. class A {
protected Object clone() {
return new A();
}
}
class B extends A implements Cloneable {
public Object clone() {
return super.clone();
}
}
.
ここでは、A
にはExceptionがスローされるため、clone
の実装が無効です。
B obj = (B)(new B()).clone();
.
代わりに、A.clone()
はコンストラクタの代わりにsuper.clone()
を呼び出す必要があります。Object.clone()
は、コンパイル時タイプの代わりにランタイムタイプの新しいオブジェクトを生成します。
任意のフィールドはこの新しいオブジェクトにクローン化されます。これは、すべてのフィールドを初期化している場合(コピーコンストラクタのような)が、サブクラスに誤った動作をもたらす場合は、コンストラクタを使用することを魅力的な場合があります。
クラスがfinal
の場合は、サブクラスを持つことができないので、問題はありません。