web-dev-qa-db-ja.com

Clone()対コンストラクターのコピー-javaで推奨

javaのクローンメソッドとコピーコンストラクタ。どちらが正しい解決策です。各ケースの使用場所

134
Jothi

クローンが壊れているので、使用しないでください。

ObjectクラスのCLONEメソッドは、純粋なJavaメソッドでは不可能だった、やや魔法的なメソッドです。オブジェクトの同一のコピーを生成します。 Javaコンパイラ*のベータリリース日以降、プリミティブオブジェクトスーパークラスに存在していました。そして、それは、すべての古代の魔法と同様に、スペルが予期せずバックファイアするのを防ぐために適切な呪文を必要とします

オブジェクトをコピーするメソッドを優先する

Foo copyFoo (Foo foo){
  Foo f = new Foo();
  //for all properties in FOo
  f.set(foo.get());
  return f;
}

続きを読む http://adtmag.com/articles/2000/01/18/effective-javaeffective-cloning.aspx

107
Tom

clone()はそのままでは機能しないことに注意してください。 Cloneableを実装し、publicで作成するclone()メソッドをオーバーライドする必要があります。

いくつかの選択肢がありますが、それは望ましいものです(他の回答で述べられているように、clone()メソッドには多くの設計上の問題があるため)。

  • BeanUtils.cloneBean(original) は、Object.clone()によって作成されたような浅いクローンを作成します。 (このクラスは commons-beanutils からのものです)

  • SerializationUtils.clone(original) は、深いクローンを作成します。 (つまり、最初のレベルだけでなく、プロパティグラフ全体が複製されます)( commons-lang から)が、すべてのクラスはSerializableを実装する必要があります

  • Java Deep Cloning Library は、Serializableを実装する必要なく、ディープクローニングを提供します。

53
Bozho

clone()は、いくつかの間違いで設計されました( この質問 を参照)。したがって、避けるのが最善です。

有効なJava第2版 、項目11:クローンを慎重にオーバーライドする

Cloneableに関連するすべての問題を考えると、他のインターフェイスはCloneableを拡張すべきではなく、継承用に設計されたクラス(項目17)はCloneableを実装すべきでないと言っても安全です。多くの欠点があるため、一部のエキスパートプログラマは、配列をコピーする場合を除いて、cloneメソッドをオーバーライドせず、cloneメソッドを呼び出さないことを選択します。継承用のクラスを設計する場合、適切に保護されたcloneメソッドを提供しないことを選択した場合、サブクラスがCloneableを実装できないことに注意してください。

この本では、コピーコンストラクターがCloneable/cloneよりも優れている点についても説明しています。

  • リスクが発生しやすい言語外オブジェクト作成メカニズムに依存していません
  • 彼らは、薄く文書化された慣習を強制できない順守を要求しません
  • 最終フィールドの適切な使用と競合しない
  • 不要なチェック済み例外をスローしません
  • 彼らはキャストを必要としません。

すべての標準コレクションには、コピーコンストラクターがあります。それらを使用します。

List<Double> original = // some list
List<Double> copy = new ArrayList<Double>(original);
32
Rose Perrone

コピーコンストラクターは、クラスタイプをコピーコンストラクターのクラスタイプに制限することに注意してください。例を考えてみましょう:

// Need to clone person, which is type Person
Person clone = new Person(person);

personPersonのサブクラスになり得る場合(またはPersonがインターフェースの場合)、これは機能しません。これがクローンのポイントです。実行時に適切な型を動的にクローンできるということです(クローンが適切に実装されていると仮定します)。

Person clone = (Person)person.clone();

または

Person clone = (Person)SomeCloneUtil.clone(person); // See Bozho's answer

personが適切に実装されていると仮定すると、Personにはcloneの任意のタイプを指定できます。

18
Steve Kuo

参照: クローンメソッドを適切にオーバーライドする方法? 。 Javaでのクローンは壊れています。それを正しくするのはとても難しいであり、それを行う場合でもそれほど多くは提供しませんなので、本当に面倒な価値はありません。

3

悲しみ:Cloneable/cloneもコンストラクタも素晴らしい解決策ではありません:実装クラスを知りたくない!!! (たとえば、同じ隠しMumbleMap実装を使用して、コピーしたいMapがあります)コピーが必要な場合は、コピーを作成したいだけです。しかし、残念ながら、Cloneableにはcloneメソッドがありません。そのため、clone()を呼び出すために安全に型キャストできるものはありません。

最高の「オブジェクトのコピー」ライブラリが何であれ、Oracleはそれを次のJavaリリースの標準コンポーネントにする必要があります(既に存在しない場合はどこかに隠されています)。

もちろん、より多くのライブラリ(たとえば、コレクション)が不変である場合、この「コピー」タスクはなくなります。しかし、その後、verdammt「bean」パターンではなく「class invariants」のようなものを使用してJavaプログラムの設計を開始します(壊れたオブジェクトを作成し、[十分]になるまで突然変異させます)。

2
Roboprog