web-dev-qa-db-ja.com

Object clone()メソッドがCloneableインターフェイスを実装するクラスでのみ使用できるのはなぜですか?

clone()が保護されたメソッドであることは知っていますが、「保護された」とは、特定のクラスのすべてのサブクラスがアクセスできることを意味します。

任意のJavaクラスはObjectのサブクラスです。では、ここで保護されたメソッドの理由は何ですか?

そして、なぜCloneableインターフェースを実装するクラスでのみclone()を呼び出すことができるのでしょうか? Objectclone()が保護されていると宣言されているという事実にどのように関連しているか理解できません。

12
Don_Quijote

オブジェクトの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); }
}
11
Cephalopod

それが彼らがそれを設計した方法だからです。バグパレードのどこかに、デザインの本来の理由が「時間の霧の中で失われている」という声明がありますが、1990年代のSunによる、デザインは4つの可能な動作を与えたという議論を覚えています。

詳細を思い出せない:-|しかし、あなたはそれを解決することができます:

  1. 何もしない。クラスのクローンを作成することはできず、派生クラスを除いてclone()メソッドにアクセスできません。
  2. 実装_Cloneable:_クラスは複製できますが、派生クラスを除いてclone()メソッドにアクセスできません。
  3. Cloneableを実装し、独自のclone()メソッドを提供します:(2)と同様ですが、clone()を公開し、正しい型を返す可能性があります。
  4. (2)または(3)を実行するクラスから派生し、clone()を実装し、_NotCloneableException:_をスローすると1に戻ります。

clone()をインターフェースに入れると、その一部が失われてしまいます。

4
user207421

Object.clone()のデフォルトの実装は、オブジェクトの基本型メソッドがそのオブジェクトの同じ型の新しいオブジェクトを生成できる唯一の方法です(おそらくReflectionを除く)。一方、派生クラスが基本クラスの不変条件に違反しない動作するcloneメソッドを実装することが不可能なクラスはたくさんあります。このような派生クラスがcloneを呼び出して、使用できない可能性のあるオブジェクトを受信できないようにすることが望まれていました。

振り返ってみると、適切なことは、保護されたCloneableObjectメソッド(Object.clone()のように機能する)を含むObjectから継承するシステムmemberwisecloneを定義することであり、他には何もありません。クローン可能になり、基本タイプとしてそれを継承します。そのタイプは、他のタイプでは使用できなかったclone()メソッド内で特別な魔法を使用できます。ただし、代わりに、システムはCloneableインターフェースの存在を使用して、オブジェクトが基本レベルのclone()メソッドの使用を許可されるかどうかを決定します。素晴らしいデザインではありませんが、それが何であるかです。壊れたオブジェクトを生成せずに派生クラスが呼び出すことができる方法があるかどうかにかかわらず、ほぼすべての派生クラスがMemberwiseCloneを呼び出すことを許可する.NETアプローチよりも良いか悪いかはわかりません。

3
supercat

Cloneableはインターフェースであり、抽象基本クラスへの参照を複製するには、基本クラスにclone()メソッドがあるか、その親の1つに公的にアクセス可能なclone()メソッドが必要です。クローン可能は、マーカーインターフェイスとして機能します。

以下を参照してください。

2
Ankit Zalani

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メソッドが反射的に呼び出されたとしても、それが成功するという保証はありません。

オブジェクトが保護されたメソッドcloneObjectCloneableを実装していなくても、あなたの質問に答えますが、clone()メソッドと呼ばれるオブジェクトは、クローン可能なinterfaceを実装する必要があります。

1
Suresh Atta