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


回答:


107

クローンが保護されているという事実は非常に疑わしいです- 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の効果的なJavaからの引用:
「Cloneableインターフェースは、オブジェクトがクローニングを許可することを宣伝するためのミックスインインターフェースとして意図されていました。残念ながら、この目的を果たすことができません...これは非常に非典型的なインターフェースの使用であり、エミュレートされるものではありません。 ...インターフェイスを実装してクラスに何らかの影響を与えるためには、インターフェイスとそのすべてのスーパークラスが、かなり複雑で、実施不可能で、ほとんど文書化されていないプロトコルに従う必要があります


2
オブジェクトがCloneableでない場合、Objectのclone()はCloneNotSupportedExceptionをスローします。したがって、super.clone()を呼び出す場合は、Cloneableである必要があります(その結果、Object.clone()が呼び出されます)。Serializableを実装せずにオブジェクトをシリアル化する方法がわかりません。
スティーブクオ

1
「Cloneableのデザインは現在、ほとんど間違いと見なされていると思います。」[引用が必要]
ケビンパンコ

すみません-私はそれを意味していませんでした。「良い」デザインとは、インターフェースを拡張しないことを意味するだけでしたSerializable実装するかどうかは実装次第Serializableです。私はこれを拡張していましたCloneable-それはインターフェースが拡張すべきものではありません-しかし、インターフェースの実装は自由Cloneableです。問題は、インターフェースタイプのパラメーターがある場合、それが複製可能かどうかを尋ねることです。しかし、実際にはそれを複製することはできません!
oxbow_lakes 2009

6
@Kevin- Josh Blochの効果的なJava pp45。「Cloneableインターフェースは、オブジェクトがクローニングを許可することを宣伝するためのミックスインインターフェースとして意図されていました。残念ながら、この目的を果たすことはできません。」
oxbow_lakes

また、同じページ:「これは非常に非典型的なインターフェースの使用であり、エミュレートされるものではありません」および「インターフェースを実装してクラスに影響を与えるためには、インターフェースとそのすべてのスーパークラスがかなり複雑でなければなりません。実施不可能でほとんど文書化されていないプロトコル "
oxbow_lakes '16 / 07/17

30

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

太陽から:

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


罰金されており、あなたがミックスにインターフェースを持参するまで -試してみて、未知の実装のクローンを作成しようとするとSet
oxbow_lakes

@oxbow_lakes:しかし、おそらくSetの一部の実装は複製できません
newacct

3
Clonableインターフェースを実装していないものはクローンできません。これは、「このクラスは適切にクローン可能」というマーカーであり、Serializableインターフェースに非常に似ています。ちなみに、シリアル化を介してクラスを複製する方法があります。「Javaシリアル化クローン」のようなGoogleのようなものを使用すると、オブジェクトの深いコピーを取得するためのいくつかの方法が見つかるはずです。
ビルK

4
Cloneableインターフェースを実装していないものは複製できませんが、Cloneableインターフェースを実装しているからといって、複製できるわけではありません。
マイケルマイヤーズ

1
@BuckCherry toStringにはデフォルトの実装があり、これを呼び出すと何か良いことが起こり、文字列が返されます。equalsにはデフォルトの実装があります(==と同じ)。クローンはデフォルトの実装を持つことができません。それを実装していないオブジェクトでcloneを呼び出すと、妥当な動作が得られません。複製は複雑であり、実際には自動的に実行することはできません(デフォルトコンストラクターのない一部のオブジェクトは、総称的に複製することが不可能である可能性があります)。ただし、Objectに配置する必要はまったくなかったと思います。
ビルK

7

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


しかし、なぜそれを保護する必要があるのでしょうか。
Janusz

3
これは保護されているので、オブジェクト内で使用しないでください(とにかく例外をスローするだけです)。彼らはあなたがクラスでそれをオーバーライドすることを望んでいる、そしてあなたはそれを公開する。(以下にも数回回答)
ビルK

1
そして、以下の私のポイントに従ってインターフェイスを検討するときは役に立たない
-oxbow_lakes

オーバーライドする必要があるかどうかはあまり明確ではないため、抽象的である必要があり、オブジェクトクラスに含めてはなりません。なぜそうなのかを理解しようとしています。
Kumar Abhishek 2017年

4

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

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

クローンの実装方法では、クローンを使用する理由と、オブジェクトのクローンを作成する方法について考えます。


2

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

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


実際、(オブジェクト内の)デフォルトの実装はドキュメントに従って例外をスローします...
Bill K

2
いいえ、投げるだけではありません。JavaDocから:「クラスObjectのメソッドcloneは特定の複製操作を実行します。最初に、このオブジェクトのクラスがインターフェースCloneableを実装していない場合、CloneNotSupportedExceptionがスローされます。すべての配列はインターフェースCloneableを実装していると見なされます。それ以外の場合、このメソッドは、このオブジェクトのクラスの新しいインスタンスを作成し、割り当てのように、このオブジェクトの対応するフィールドの内容ですべてのフィールドを初期化します。フィールドの内容自体は複製されません。」
Pavel Minaev 2009

2

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
保護されているため、すべてのオブジェクトでクローンを呼び出すことはできません
Pavel Minaev 2009

2

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

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

他のクラスではなく、サブクラスから呼び出すことができるメソッドの適切なスコープは何ですか?

ですprotected

Cloneableもちろん、実装するクラスはこのメソッドをパブリックにするので、他のクラスから呼び出すことができます。


0

Clone()メソッドには、内部的に「Cloneableのインスタンスかどうか」のチェックがあります。これは、Javaチームがclone()メソッドの不適切な使用を制限すると考えられる方法です。clone()メソッドは保護されています。つまり、サブクラスのみによってアクセスされます。オブジェクトはすべてのサブクラスの親クラスであるため、上記の「Cloneableのインスタンス」のチェックを行わなければ、Clone()メソッドはすべてのクラスでそのまま使用できます。これが、Javaチームがclone()メソッドに「Cloneableのインスタンスかどうか」をチェックさせることで、clone()の不適切な使用を制限しようと考えた理由です。

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

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


-2

はい、私が会った同じ問題。しかし、私はこのコードを実装することでそれを解決します

public class Side implements Cloneable {
    public Side clone() {

        Side side = null;
        try {
            side = (Side) super.clone();
        } catch (CloneNotSupportedException e) {
            System.err.println(e);
        }
        return side;
    }
}

以前と同じように誰かが言った。


1
CloneNotSupportedExceptionは、チェックされていないはずのチェックされた例外の別の例です(つまり、Exceptionではなく、RuntimeExceptionを拡張する必要があります)。Sideクラスのclone()メソッドはCloneableを実装するため、CloneNotSupportedExceptionをスローすることはありませんが、Side.clone()は例外をキャッチまたは宣言する必要があります。これは、clone()メソッドに余分な例外処理ノイズを追加するだけです。
Derek Mahar、

-2

まあ、太陽の開発者も人間だけであり、実際にはクローンメソッドを保護されたものとして実装するのに大きな間違いを犯しました。これは、機能しないクローンメソッドをArrayListに実装したのと同じ間違いです!そのため、一般に、クローンメソッドについては、経験豊富なJavaプログラマでさえも、より深い誤解があります。

ただし、私は最近、オブジェクトがどのように構築され、何が含まれているかに関係なく、オブジェクトとそのすべてのコンテンツをコピーするための高速で簡単なソリューションを見つけました。ここで私の答えを参照してください:Object.clone()の使用におけるバグ


-3

繰り返しますが、Java JDKフレームワークは見事な考え方を示しています。

クローン可能なインターフェースには、「public T clone();」が含まれていません。これは、インスタンスを複製できる属性(Serializableなど)のように機能するためです。

このデザインには何も問題はありません。

  1. Object.clone()は、カスタム定義クラスで必要なことを行いません。

  2. MyclassがCloneable =>を実装している場合、「public MyClass clone()」でclone()を上書きします

  3. MyInterfaceがCloneableを拡張し、一部のMyClassesがMyInterfaceを実装している場合: "public MyInterface clone();"を定義するだけです。インターフェースでは、MyInterfaceオブジェクトを使用するすべてのメソッドは、それらのMyClassクラスに関係なく、それらを複製できます。


2
クラスが継承された場合、派生クラスの複製の実装は、基本クラスの実装が安全な複製メソッドを提供するまで安全ではありません。また、メソッド/属性のないインターフェイスを持つことは、通常とは異なる設計条件です。このインターフェイスは、クラスにクローンの実装を強制しません。
prap19
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.