web-dev-qa-db-ja.com

クラスにCloneableを実装させることのポイントは何ですか?

Clonableを実装するクラスコードに出くわしました、ドキュメントには次のように記載されています。

クラスはCloneableインターフェースを実装して、そのメソッドがそのクラスのインスタンスのフィールドごとのコピーを作成することが合法であることをObject.clone()メソッドに示します。 Cloneableインターフェイスを実装していないインスタンスでObjectのcloneメソッドを呼び出すと、例外CloneNotSupportedExceptionがスローされます。慣例により、このインターフェイスを実装するクラスは、パブリックメソッドでObject.clone(保護されている)をオーバーライドする必要があります。このメソッドのオーバーライドの詳細については、Object.clone()を参照してください。このインターフェースにはcloneメソッドが含まれていないことに注意してください。したがって、オブジェクトがこのインターフェイスを実装しているという事実だけでオブジェクトを複製することはできません。 cloneメソッドが反射的に呼び出されたとしても、それが成功するという保証はありません。

ドキュメントに記載されているように、このクラスを実装する意味が理解できません。.cloneメソッドはインターフェイスに実装されていないため、実装する必要があります。では、なぜこのクラスを使用するのでしょうか。このクラスを実装せずに、クラスにメソッドcopyClassを記述して、オブジェクトのコピーを作成しないのはなぜですか?

19
Emil Adz

Cloneメソッドを実装するには、次のようにします。

_public Object clone() throws CloneNotSupportedException {
    return super.clone();
}
_

もちろん、必要に応じてメソッドをカスタマイズして、より深いコピーを作成することもできます。

super.clone()の呼び出しはほぼ必須です。クラスがfinalであり、オーバーライドできない場合を除いて、clone()メソッドは、呼び出されたオブジェクトと同じクラスのインスタンスを返す必要があるためです。 。したがって、新しいインスタンスを作成して状態をコピーするだけで、このクラスでは機能しますが、すべてのサブクラスで機能するわけではありません。さらに、スーパークラスに含まれるすべての状態に常にアクセスできるとは限りません。

つまり、Objectの保護されたクローンメソッドをパブリックにします。そして、Object.clone()メソッドが最初に行うことは次のとおりです(これは実際のコードではありませんが、これはメソッドが行うことです)。

_if (!(this instanceof Cloneable)) {
    throw new CloneNotSupportedException();
}
_

したがって、Cloneableは、Object.clone()メソッドが呼び出されたときに例外をスローしてはならないことを知らせるための単なるマーカーインターフェイスです。

これは、Javaの最も不適切に設計された部分の1つです。通常、clone()を使用する代わりに、コピーコンストラクターを使用することをお勧めします。

29
JB Nizet

これにより、より一般的なコードを記述できます。 Cloneableインターフェイスを実装する複数のクラスがあり、それらのインスタンスをメソッドへの引数として渡したい場合は、1つの変数タイプが異なる複数のメソッドを作成する必要はありません。Cloneable tを使用するだけです。 。他のインターフェースでも同じです。そして、他のすべてのインターフェースと同じように、それは一種の多重継承です。これらのインターフェースを実装すると、コードも読みやすくなります。

1
Mateusz

他の人が言ったことに加えて、Cloneableはプロトタイプデザインパターンを実装するときによく使用されます。