回答:
アイテムを反復処理し、1つずつクローンを作成して、結果の配列にクローンを配置する必要があります。
public static List<Dog> cloneList(List<Dog> list) {
List<Dog> clone = new ArrayList<Dog>(list.size());
for (Dog item : list) clone.add(item.clone());
return clone;
}
これを機能させるには、明らかに、Dog
クラスにCloneable
インターフェースを実装させ、clone()
メソッドをオーバーライドする必要があります。
私は個人的に、Dogにコンストラクタを追加します。
class Dog
{
public Dog()
{ ... } // Regular constructor
public Dog(Dog dog) {
// Copy all the fields of Dog.
}
}
次に、単に繰り返します(Varkhanの回答に示されています)。
public static List<Dog> cloneList(List<Dog> dogList) {
List<Dog> clonedList = new ArrayList<Dog>(dogList.size());
for (Dog dog : dogList) {
clonedList.add(new Dog(dog));
}
return clonedList;
}
これの利点は、Javaで壊れたCloneableをいじる必要がないことです。また、Javaコレクションをコピーする方法にも一致します。
別のオプションは、独自のICloneableインターフェイスを作成してそれを使用することです。このようにして、クローン作成のための汎用メソッドを作成できます。
cloneList(List<Object>)
かDog(Object)
?
すべての標準コレクションには、コピーコンストラクタがあります。それらを使用してください。
List<Double> original = // some list
List<Double> copy = new ArrayList<Double>(original); //This does a shallow copy
clone()
は、いくつかの間違い(この質問を参照)で設計されたので、それを避けるのが最善です。
以下からの効果的なJavaの第2版、項目11:オーバーライドクローン慎重
Cloneableに関連するすべての問題を考えると、他のインターフェースはそれを拡張してはならず、継承用に設計されたクラス(項目17)はそれを実装すべきではないと言っても安全です。多くの欠点があるため、一部のエキスパートプログラマーは、クローンメソッドをオーバーライドせず、配列をコピーする場合を除いて、クローンメソッドを呼び出さないことを選択しています。継承用のクラスを設計する場合、適切に動作する保護されたクローンメソッドを提供しないことを選択すると、サブクラスがCloneableを実装することが不可能になることに注意してください。
この本では、コピーコンストラクターがCloneable / cloneを超える多くの利点についても説明しています。
コピーコンストラクターを使用する別の利点を検討してください:がありHashSet s
、それをとしてコピーするとしTreeSet
ます。cloneメソッドはこの機能を提供できませんが、変換コンストラクターを使用すると簡単ですnew TreeSet(s)
。
Java 8は、要素dogsのコピーコンストラクターまたはクローンメソッドをエレガントかつコンパクトに呼び出す新しい方法を提供します:Streams、lambdasおよびcollectors。
コピーコンストラクタ:
List<Dog> clonedDogs = dogs.stream().map(Dog::new).collect(toList());
この式Dog::new
は、メソッド参照と呼ばれます。Dog
別の犬を引数にとるコンストラクタを呼び出す関数オブジェクトを作成します。
クローン方法[1]:
List<Dog> clonedDogs = dogs.stream().map(d -> d.clone()).collect(toList());
ArrayList
結果または、ArrayList
(後で変更する場合に備えて)取り戻す必要がある場合:
ArrayList<Dog> clonedDogs = dogs.stream().map(Dog::new).collect(toCollection(ArrayList::new));
dogs
リストの元のコンテンツを保持する必要がない場合は、代わりにreplaceAll
メソッドを使用して、リストを適切に更新できます。
dogs.replaceAll(Dog::new);
すべての例はを想定していimport static java.util.stream.Collectors.*;
ます。
ArrayList
Sのコレクター最後の例のコレクターは、utilメソッドにすることができます。これは非常に一般的なことなので、個人的には短くてかわいいことが好きです。このような:
ArrayList<Dog> clonedDogs = dogs.stream().map(d -> d.clone()).collect(toArrayList());
public static <T> Collector<T, ?, ArrayList<T>> toArrayList() {
return Collectors.toCollection(ArrayList::new);
}
CloneNotSupportedException
:このソリューションが機能するclone
ためには、メソッドがスローすることを宣言してはDog
なりませんCloneNotSupportedException
。その理由は、への引数がmap
チェックされた例外をスローすることを許可されていないためです。
このような:
// Note: Method is public and returns Dog, not Object
@Override
public Dog clone() /* Note: No throws clause here */ { ...
とにかく、これはベストプラクティスであるため、これは大きな問題にはなりません。(例えばEffectice Javaがこのアドバイスを提供します。)
これを指摘してくれたGustavoに感謝します。
見栄えが良い場合は、代わりにメソッド参照構文を使用してまったく同じことを実行できます。
List<Dog> clonedDogs = dogs.stream().map(Dog::clone).collect(toList());
List<Dog> clonedDogs = new ArrayList<>(); dogs.stream().parallel().forEach(d -> clonedDogs.add(new Dog(d)));
parallel
呼び出しがclonedDogs.add
複数のスレッドから同時に呼び出されるためです。を使用collect
するバージョンはスレッドセーフです。これは、ストリームライブラリの機能モデルの利点の1つです。同じコードを並列ストリームに使用できます。
Unhandled exception type CloneNotSupportedException
オンになりd.clone()
ます。例外を宣言またはキャッチしても解決されません。
Dog
この例では)はクローンをサポートしていません。それはClonable
インターフェースを実装していますか?
基本的に、手動で繰り返すことなく3つの方法があります。
1コンストラクターの使用
ArrayList<Dog> dogs = getDogs();
ArrayList<Dog> clonedList = new ArrayList<Dog>(dogs);
2使用 addAll(Collection<? extends E> c)
ArrayList<Dog> dogs = getDogs();
ArrayList<Dog> clonedList = new ArrayList<Dog>();
clonedList.addAll(dogs);
3 パラメータaddAll(int index, Collection<? extends E> c)
付きのメソッドの使用int
ArrayList<Dog> dogs = getDogs();
ArrayList<Dog> clonedList = new ArrayList<Dog>();
clonedList.addAll(0, dogs);
注意:指定されたコレクションが操作の進行中に変更された場合、これらの操作の動作は未定義になります。
私は現在の緑の答えは悪いと思います、なぜあなたは尋ねるかもしれませんか?
シリアライゼーションも悪い方法ですが、どこでもSerializableを追加する必要があるかもしれません。
だから解決策は何ですか?
Javaディープクローンライブラリ クローンライブラリは、オブジェクトをディープクローンする小さなオープンソース(Apacheライセンス)Javaライブラリです。オブジェクトはCloneableインターフェースを実装する必要はありません。事実上、このライブラリは任意のJavaオブジェクトを複製できます。キャッシュされたオブジェクトを変更したくない場合や、オブジェクトのディープコピーを作成したい場合は、キャッシュ実装で使用できます。
Cloner cloner=new Cloner();
XX clone = cloner.deepClone(someObjectOfTypeXX);
私は方法を見つけました、jsonを使用してリストをシリアル化/シリアル化解除できます。シリアル化されたリストは、シリアル化されていない場合、元のオブジェクトへの参照を保持しません。
gsonの使用:
List<CategoryModel> originalList = new ArrayList<>(); // add some items later
String listAsJson = gson.toJson(originalList);
List<CategoryModel> newList = new Gson().fromJson(listAsJson, new TypeToken<List<CategoryModel>>() {}.getType());
ジャクソンと他のjsonライブラリを使用してそれを行うこともできます。
厄介な方法は、反射でそれを行うことです。このようなことがうまくいきました。
public static <T extends Cloneable> List<T> deepCloneList(List<T> original) {
if (original == null || original.size() < 1) {
return new ArrayList<>();
}
try {
int originalSize = original.size();
Method cloneMethod = original.get(0).getClass().getDeclaredMethod("clone");
List<T> clonedList = new ArrayList<>();
// noinspection ForLoopReplaceableByForEach
for (int i = 0; i < originalSize; i++) {
// noinspection unchecked
clonedList.add((T) cloneMethod.invoke(original.get(i)));
}
return clonedList;
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
System.err.println("Couldn't clone list due to " + e.getMessage());
return new ArrayList<>();
}
}
original
異なるクラスのオブジェクトが含まれている場合cloneMethod.invoke
、間違った種類のオブジェクトで呼び出されると例外で失敗すると思います。このため、Method
オブジェクトごとに特定のクローンを取得する方がよい場合があります。または、クローンメソッドを使用しますObject
(ただし、保護されているため、失敗する可能性が高くなります)。
一般的なテンプレートタイプを使用したソリューションを次に示します。
public static <T> List<T> copyList(List<T> source) {
List<T> dest = new ArrayList<T>();
for (T item : source) { dest.add(item); }
return dest;
}
commons-lang-2.3.jarを使用して、Javaのライブラリがリストを複製する簡単な方法
使い方
oldList.........
List<YourObject> newList = new ArrayList<YourObject>();
foreach(YourObject obj : oldList){
newList.add((YourObject)SerializationUtils.clone(obj));
}
これがお役に立てば幸いです。
:D
その包み import org.apache.commons.lang.SerializationUtils;
方法があります SerializationUtils.clone(Object);
例
this.myObjectCloned = SerializationUtils.clone(this.object);
エンティティオブジェクトとjava.util.Listオブジェクトのクローンを作成できるlibを開発しました。https://drive.google.com/open?id=0B69Sui5ah93EUTloSktFUkctN0Uでjarをダウンロードし、静的メソッドcloneListObject(List list)を使用するだけです。このメソッドは、Listを複製するだけでなく、すべてのエンティティ要素も複製します。
以下は私のために働いた。
Dog.java
public Class Dog{
private String a,b;
public Dog(){} //no args constructor
public Dog(Dog d){ // copy constructor
this.a=d.a;
this.b=d.b;
}
}
-------------------------
private List<Dog> createCopy(List<Dog> dogs) {
List<Dog> newDogsList= new ArrayList<>();
if (CollectionUtils.isNotEmpty(dogs)) {
dogs.stream().forEach(dog-> newDogsList.add((Dog) SerializationUtils.clone(dog)));
}
return newDogsList;
}
ここでは、createCopyメソッドから作成された新しいリストがSerializationUtils.clone()を介して作成されます。したがって、新しいリストに加えられた変更は、元のリストには影響しません
ディープコピーArrayListを作成する本当に簡単な方法を見つけたと思います。String ArrayList arrayAをコピーするとします。
ArrayList<String>arrayB = new ArrayList<String>();
arrayB.addAll(arrayA);
うまくいかない場合はお知らせください。