clone()
が保護されたメソッドであることは知っていますが、「保護された」とは、特定のクラスのすべてのサブクラスがアクセスできることを意味します。
任意のJavaクラスはObject
のサブクラスです。では、ここで保護されたメソッドの理由は何ですか?
そして、なぜCloneable
インターフェースを実装するクラスでのみclone()
を呼び出すことができるのでしょうか? Object
のclone()
が保護されていると宣言されているという事実にどのように関連しているか理解できません。
オブジェクトのclone()メソッドは、すべてのフィールドがコピーされた(finalも含む)現在のクラスのインスタンスを常に返すため、非常に特殊です。プレーンなJavaコードで、リフレクションを使用しても、これを再現することは不可能だと思います。
このため、すべてのクラスで使用できるようにする必要がありますが、すべてを複製可能にしたくないため、デフォルトでは外部から呼び出すことができないため、保護する必要があります。
追加のチェックとして、clone
はクラスがCloneable
を実装していることをチェックしますが、誤ってクローンできないものをクローンしないようにするためだけです。
全体として、最終フィールドをディープコピーする必要がある場合は機能しないため、クローン作成は多少壊れています。このパターンに従って、インスタンスのコピーを手動で実装することをお勧めします。
public class Base {
/** one or more public constructors */
public Base() { ... }
/** copy-constructor */
protected Base(Base src) { /* copy or deep-copy the state */ }
public Base copy() { return new Base(this); }
}
public class Derived extends Base {
/** one or more public constructors */
public Derived() { ... }
/** copy-constructor */
protected Derived(Derived src) {
super(src);
/* copy or deep-copy the state */
}
@Override
public Derived copy() { return new Derived(this); }
}
それが彼らがそれを設計した方法だからです。バグパレードのどこかに、デザインの本来の理由が「時間の霧の中で失われている」という声明がありますが、1990年代のSunによる、デザインは4つの可能な動作を与えたという議論を覚えています。
詳細を思い出せない:-|しかし、あなたはそれを解決することができます:
clone()
メソッドにアクセスできません。Cloneable:
_クラスは複製できますが、派生クラスを除いてclone()
メソッドにアクセスできません。Cloneable
を実装し、独自のclone()
メソッドを提供します:(2)と同様ですが、clone()
を公開し、正しい型を返す可能性があります。clone()
を実装し、_NotCloneableException:
_をスローすると1に戻ります。clone()
をインターフェースに入れると、その一部が失われてしまいます。
Object.clone()
のデフォルトの実装は、オブジェクトの基本型メソッドがそのオブジェクトの同じ型の新しいオブジェクトを生成できる唯一の方法です(おそらくReflectionを除く)。一方、派生クラスが基本クラスの不変条件に違反しない動作するclone
メソッドを実装することが不可能なクラスはたくさんあります。このような派生クラスがclone
を呼び出して、使用できない可能性のあるオブジェクトを受信できないようにすることが望まれていました。
振り返ってみると、適切なことは、保護されたCloneableObject
メソッド(Object.clone()
のように機能する)を含むObject
から継承するシステムmemberwiseclone
を定義することであり、他には何もありません。クローン可能になり、基本タイプとしてそれを継承します。そのタイプは、他のタイプでは使用できなかったclone()
メソッド内で特別な魔法を使用できます。ただし、代わりに、システムはCloneable
インターフェースの存在を使用して、オブジェクトが基本レベルのclone()
メソッドの使用を許可されるかどうかを決定します。素晴らしいデザインではありませんが、それが何であるかです。壊れたオブジェクトを生成せずに派生クラスが呼び出すことができる方法があるかどうかにかかわらず、ほぼすべての派生クラスがMemberwiseClone
を呼び出すことを許可する.NETアプローチよりも良いか悪いかはわかりません。
Cloneableはインターフェースであり、抽象基本クラスへの参照を複製するには、基本クラスにclone()メソッドがあるか、その親の1つに公的にアクセス可能なclone()メソッドが必要です。クローン可能は、マーカーインターフェイスとして機能します。
以下を参照してください。
http://docs.Oracle.com/javase/7/docs/api/Java/lang/Cloneable.html
クラスはCloneableインターフェースを実装して、そのメソッドがそのクラスのインスタンスのフィールドごとのコピーを作成することが合法であることをObject.clone()メソッドに示します。 Cloneableインターフェイスを実装していないインスタンスでObjectのcloneメソッドを呼び出すと、例外CloneNotSupportedExceptionがスローされます。
慣例により、このインターフェイスを実装するクラスは、パブリックメソッドでObject.clone(保護されている)をオーバーライドする必要があります。このメソッドのオーバーライドの詳細については、Object.clone()を参照してください。
このインターフェースにはcloneメソッドが含まれていないことに注意してください。したがって、オブジェクトがこのインターフェイスを実装しているという事実だけでオブジェクトのクローンを作成することはできません。 cloneメソッドが反射的に呼び出されたとしても、それが成功するという保証はありません。
オブジェクトが保護されたメソッドclone
Object
はCloneable
を実装していなくても、あなたの質問に答えますが、clone()
メソッドと呼ばれるオブジェクトは、クローン可能なinterface
を実装する必要があります。