どうやってArrayList
のクローンを作成し、さらにその項目をJavaでクローンすることができますか?
たとえば、私は持っています:
ArrayList<Dog> dogs = getDogs();
ArrayList<Dog> clonedList = ....something to do with dogs....
そしてclonedList
の中のオブジェクトは、犬のリストの中のものと同じではないと私は思います。
あなたはアイテムをイテレートし、それらを一つずつクローンし、あなたが行くようにクローンを結果配列に入れる必要があるでしょう。
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インターフェースを書いてそれを使うことかもしれません。そうすれば、クローン作成のための一般的な方法を書くことができます。
すべての標準コレクションにはコピーコンストラクタがあります。それらを使ってください。
List<Double> original = // some list
List<Double> copy = new ArrayList<Double>(original); //This does a shallow copy
clone()
はいくつかの間違いで設計されています( この質問を参照してください )ので、避けることをお勧めします。
有効なJava 2nd Edition 、項目11から:クローンを慎重に上書きする
Cloneableに関連するすべての問題を考えると、他のインターフェースがそれを拡張するべきではなく、継承のために設計されたクラス(Item 17)がそれを実装するべきではないと言っても安全です。その多くの欠点のために、何人かの熟練したプログラマーはクローンメソッドを決して上書きせず、そして決して呼び出すことを決して選ばない、おそらく配列をコピーすることを除いて。継承用のクラスを設計する場合は、適切に保護された保護クローンメソッドを提供しないことを選択した場合、サブクラスでCloneableを実装することは不可能になります。
この本はまたコピーコンストラクタがCloneable/cloneよりも優れている多くの利点について説明します。
コピーコンストラクタを使用するもう1つの利点を考えます。HashSet s
があり、それをTreeSet
としてコピーするとします。 cloneメソッドはこの機能を提供できませんが、変換コンストラクタnew TreeSet(s)
を使うと簡単です。
Java 8では、要素dogのコピーコンストラクタまたはcloneメソッドをエレガントかつコンパクトに呼び出すための新しい方法が提供されています。 Streams、ラムダおよびコレクタ 。
コピーコンストラクタ:
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());
基本的に、手動で繰り返すことなく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 int
パラメータを指定したaddAll(int index, Collection<? extends E> c)
メソッドの使用
ArrayList<Dog> dogs = getDogs();
ArrayList<Dog> clonedList = new ArrayList<Dog>();
clonedList.addAll(0, dogs);
注意:指定したコレクションが操作の進行中に変更された場合、これらの操作の動作は不定になります。
現在の緑色の答えは悪いと思います、なぜあなたは尋ねるのですか?
シリアライゼーションも悪い方法です、あなたは至る所にシリアライズ可能を追加しなければならないかもしれません。
だから解決策は何ですか:
Javaディープクローニングライブラリクローニングライブラリは、オブジェクトをディープクローンするための小型のオープンソース(Apacheライセンス)Javaライブラリです。オブジェクトはCloneableインタフェースを実装する必要はありません。事実上、このライブラリはあらゆるJavaオブジェクトを複製することができます。キャッシュされたオブジェクトを変更したくない場合や、オブジェクトのディープコピーを作成したい場合はいつでも、キャッシュ実装で使用できます。
Cloner cloner=new Cloner();
XX clone = cloner.deepClone(someObjectOfTypeXX);
https://github.com/kostaskougios/cloning でチェックしてください。
私は方法を見つけました、あなたはリストをシリアライズ/アンシリアライズするために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());
あなたはjacksonや他のjsonライブラリを使ってもそれができます。
clone()
はあなたのためにそれをしないので、あなたはArrayList
を手作業で複製する必要があるでしょう(それを反復して各要素を新しいArrayList
にコピーすることによって)。これは、ArrayList
に含まれるオブジェクトがそれ自身をClonable
に実装していない可能性があるためです。
編集:...それがまさにVarkhanのコードの動作です。
厄介な方法は反射でそれを行うことです。このようなものは私のために働いた。
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<>();
}
}
パッケージimport org.Apache.commons.lang.SerializationUtils;
SerializationUtils.clone(Object);
というメソッドがあります
例
this.myObjectCloned = SerializationUtils.clone(this.object);
他のポスターは正しいです:あなたはリストを繰り返して新しいリストにコピーする必要があります。
ただし、リスト内のオブジェクトが不変の場合は、複製する必要はありません。あなたのオブジェクトが複雑なオブジェクトグラフを持っているならば - それらも不変である必要があるでしょう。
不変性のもう1つの利点は、スレッドセーフでもあることです。
Commons-lang-2.3.jarを使ってJavaのライブラリをクローンリストにする簡単な方法
link ダウンロードcommons-lang-2.3.jar
使い方
oldList.........
List<YourObject> newList = new ArrayList<YourObject>();
foreach(YourObject obj : oldList){
newList.add((YourObject)SerializationUtils.clone(obj));
}
これが役に立つことを願っています。
:D
エンティティオブジェクトとJava.util.Listオブジェクトを複製できるライブラリを開発しました。 https://drive.google.com/open?id=0B69Sui5ah93EUTloSktFUkctN0U からjarをダウンロードして、静的メソッドcloneListObject(List list)を使用するだけです。このメソッドは、Listだけでなくすべてのエンティティ要素も複製します。
これは一般的なテンプレートタイプを使った解決策です:
public static <T> List<T> copyList(List<T> source) {
List<T> dest = new ArrayList<T>();
for (T item : source) { dest.add(item); }
return dest;
}
私はこのオプションをいつも使っています:
ArrayList<Dog> clonedList = new ArrayList<Dog>(name_of_arraylist_that_you_need_to_Clone);
あなたのオブジェクトはclone()メソッドをオーバーライドします
class You_class {
int a;
@Override
public You_class clone() {
You_class you_class = new You_class();
you_class.a = this.a;
return you_class;
}
}
vector objまたはArraiList obj ....に対して.clone()を呼び出します。