web-dev-qa-db-ja.com

clone()メソッドがJava.lang.Objectで保護されているのはなぜですか?

clone()Java.lang.Objectで保護されていると定義されている具体的な理由は何ですか?

104
Alex N.

クローンが保護されているという事実は非常に疑わしい-cloneメソッドがCloneableインターフェイスで宣言されていないという事実と同様です。

言うことはできませんであるため、データのコピーを取得するためにメソッドがかなり役に立たなくなります。

if(a instanceof Cloneable) {
    copy = ((Cloneable) a).clone();
}

Cloneableの設計は、今では大部分は間違いと見なされています(以下の引用)であると思います。私は通常、インターフェースCloneableの実装を作成できるようにしたいと思いますが、必ずしもインターフェースCloneableを作成するわけではありません( Serializable)の使用に似ています。これはリフレクションなしでは実行できません。

ISomething i = ...
if (i instanceof Cloneable) {
   //DAMN! I Need to know about ISomethingImpl! Unless...
   copy = (ISomething) i.getClass().getMethod("clone").invoke(i);
}

引用元Josh BlochのEffective Java
"Cloneableインターフェースは、オブジェクトがクローンを許可することを宣伝するためのmixinインターフェースとして意図されていました。残念ながら、この目的を果たすことができません...インターフェースをエミュレートするのではなく...インターフェースを実装してクラスに影響を与えるためには、インターフェースとそのすべてのスーパークラスがかなり複雑で、強制力がなく、ほとんど文書化されていないプロトコル "

104
oxbow_lakes

Clonableインターフェースは、クラスがクローンをサポートできることを示す単なるマーカーです。このメソッドは、オブジェクトで呼び出すべきではなく、パブリックとしてオーバーライドできるため、保護されています。

太陽から:

クラスObjectでは、clone()メソッドはprotectedと宣言されています。 Cloneableを実装するだけであれば、同じパッケージのサブクラスとメンバーのみがオブジェクトでclone()を呼び出すことができます。パッケージ内のクラスがclone()メソッドにアクセスできるようにするには、以下で行うように、それをオーバーライドしてpublicとして宣言する必要があります。 (メソッドをオーバーライドする場合、プライベートにすることはできますが、プライベートにすることはできません。ここでは、Objectのprotected clone()メソッドがパブリックメソッドとしてオーバーライドされています。)

27
Bill K

cloneは、現在のクラスに固有になるようにオーバーライドする必要があるため、保護されています。オブジェクトを複製するpublic cloneメソッドを作成することは可能ですが、これを必要とするクラス専用に作成されたメソッドほど優れていません。

7
Andrew Hare

Cloneメソッドはどのオブジェクトにも直接使用できません。そのため、サブクラスでオーバーライドすることを目的としています。

もちろん、それは公開される可能性があり、クローニングが不可能な場合に適切な例外をスローするだけですが、それは誤解を招くと思います。

クローンの実装方法により、クローンを使用する理由と、オブジェクトをクローンする方法を考えることができます。

4
Silfverstrom

デフォルトの実装では、すべてのフィールド(プライベートを含む)、迂回コンストラクタのメンバーごとの浅いコピーを行うため、保護されています。これは、オブジェクトがそもそも処理するように設計されているものではありません(たとえば、共有リスト内の作成されたオブジェクトインスタンス、または類似のものを追跡する場合があります)。

同じ理由で、呼び出されたオブジェクトがCloneableを実装していない場合、clone()のデフォルト実装はスローされます。これは潜在的に危険な操作であり、結果は広範囲に及ぶため、クラスの作成者は明示的にオプトインする必要があります。

2
Pavel Minaev

Cloneableのjavadocから。

* By convention, classes that implement this interface (cloneable) should override 
* <tt>Object.clone</tt> (which is protected) with a public method.
* See {@link Java.lang.Object#clone()} for details on overriding this
* method.

* Note that this interface does <i>not</i> contain the <tt>clone</tt> method.
* Therefore, it is not possible to clone an object merely by virtue of the
* fact that it implements this interface.  Even if the clone method is invoked
* reflectively, there is no guarantee that it will succeed.

したがって、すべてのオブジェクトでcloneを呼び出すことができますが、これはほとんどの場合、必要な結果や例外ではありません。ただし、クローン可能を実装する場合にのみ推奨されます。

2
Janusz

私見それはこれと同じくらい簡単です:

  • #cloneは、クローン不可オブジェクトで呼び出されてはならないため、公開されません。
  • #cloneは、適切なクラスの浅いコピーを取得するためにCloneableを実装するサブクラスob Objectによって呼び出される必要があります

サブクラスからは呼び出せるが、他のクラスからは呼び出せないメソッドの正しいスコープは何ですか?

protectedです。

もちろんCloneableを実装するクラスは、このメソッドをパブリックにして、他のクラスから呼び出せるようにします。

Clone()メソッドは内部的に「Cloneableのインスタンスかどうか」をチェックします。これは、Javaチームがclone()method.clone()メソッドの不適切な使用を制限すると考えられる方法です。オブジェクトはすべてのサブクラスの親クラスであるため、Clone()メソッドは、「Cloneableのインスタンス」のチェックがない場合、すべてのクラスの実際に使用できます。これが理由Javaチームは、clone()メソッド「is it Cloneableのインスタンス」でチェックを行うことにより、clone()の不適切な使用を制限すると考えたかもしれません。

したがって、cloneableを実装するクラスはすべて、Objectクラスのclone()メソッドを使用できます。

また、保護されているため、クローン可能なインターフェイスを実装するサブクラスでのみ使用できます。パブリックにしたい場合、このメソッドは、独自の実装を持つサブクラスでオーバーライドする必要があります。

0
SARIKA