1

私はEffective Javaの本を読みましたが、Clonableインターフェースを説明している段落が1つ理解できません。誰かが私にこの段落を説明できますか:

...プログラマーは、クラスを拡張してサブクラスから呼び出す場合 super.clone、返されるオブジェクトはサブクラスのインスタンスになると想定しています。スーパークラスがこの機能を提供できる唯一の方法は、 を呼び出して取得したオブジェクトを返すことsuper.cloneです。clone メソッドがコンストラクターによって作成されたオブジェクトを返す場合、そのオブジェクトのクラスは間違っています。

ありがとう。

4

3 に答える 3

6

cloneまず、それ自体が壊れていること、およびコピー コンストラクターのようなものは、コントラクトが非常に弱いことを考えると、Sheep(Sheep cloneMe)よりもはるかにエレガントなイディオムであることに注意してください。この本を読んでいるので、おそらくすでにこれを知っているでしょうが、ここに入れる価値があります。cloneCloneable

とにかく、質問に答えるには:

Object.clone()呼び出されたオブジェクトと同じタイプのオブジェクトを作成します。このため、Object返す予定の結果を取得するために「カスケード」することを強くお勧めします。誰かがこの規則に従わないと決めた場合、規則を破ったクラスの型のオブジェクトになってしまい、多くの問題が発生します。

説明するために、私はそのようなクラスを持っています

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

dolly.clone()返されるのはSheepではなく であるため、例外が発生しますWoolySheep

于 2012-07-25T16:21:24.427 に答える
2

@corsiKaの答えには同意しません。Java5.0以降。Java は共変の戻り値の型をサポートしているため、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.
    }
}

また、推奨される代替コピー コンストラクターはポリモーフィズムをサポートしていません。次の例を検討してください(コピーコンストラクターでは実行できません):

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();
  }
}
于 2017-10-31T22:09:20.067 に答える
1
class A {
    protected Object clone() {
        return new A();
    }
}

class B extends A implements Cloneable {
    public Object clone() {
        return super.clone();
    }
}

ここでは、例外がスローされるためA、 の無効な実装があります。clone

B obj = (B)(new B()).clone();

代わりに、コンストラクターの代わりにA.clone()呼び出す必要があります。次に、コンパイル時型ではなく実行時型の新しいオブジェクトを生成します。super.clone()Object.clone()

次に、すべてのフィールドがこの新しいオブジェクトに複製されます。すべてのフィールドを初期化するコンストラクター (コピー コンストラクターなど) が既にある場合は、コンストラクターを使用したくなるかもしれませんが、サブクラスの動作が正しくなくなります。

クラスが の場合、finalサブクラスを持つことはできないため、問題ありません。

于 2012-07-25T16:29:46.407 に答える