web-dev-qa-db-ja.com

ArrayListを複製し、その内容も複製する方法は?

どうやってArrayListのクローンを作成し、さらにその項目をJavaでクローンすることができますか?

たとえば、私は持っています:

ArrayList<Dog> dogs = getDogs();
ArrayList<Dog> clonedList = ....something to do with dogs....

そしてclonedListの中のオブジェクトは、犬のリストの中のものと同じではないと私は思います。

247
palig

あなたはアイテムをイテレートし、それらを一つずつクローンし、あなたが行くようにクローンを結果配列に入れる必要があるでしょう。

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()メソッドをオーバーライドさせる必要があります。

186
Varkhan

私は、個人的には、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インターフェースを書いてそれを使うことかもしれません。そうすれば、クローン作成のための一般的な方法を書くことができます。

187
cdmckay

すべての標準コレクションにはコピーコンストラクタがあります。それらを使ってください。

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)を使うと簡単です。

135
Rose Perrone

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.*;を想定しています。


ArrayListsのコレクター

最後の例のコレクターは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);
}

[1] CloneNotSupportedExceptionに関するメモ:

このソリューションが機能するためには、cloneDogメソッドが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());
36
Lii

基本的に、手動で繰り返すことなく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);

注意:指定したコレクションが操作の進行中に変更された場合、これらの操作の動作は不定になります。

28
javatar

現在の緑色の答えは悪いと思います、なぜあなたは尋ねるのですか?

  • 多くのコードを追加する必要があるかもしれません
  • コピーするすべてのリストを一覧表示してこれを実行する必要があります。

シリアライゼーションも悪い方法です、あなたは至る所にシリアライズ可能を追加しなければならないかもしれません。

だから解決策は何ですか:

Javaディープクローニングライブラリクローニングライブラリは、オブジェクトをディープクローンするための小型のオープンソース(Apacheライセンス)Javaライブラリです。オブジェクトはCloneableインタフェースを実装する必要はありません。事実上、このライブラリはあらゆるJavaオブジェクトを複製することができます。キャッシュされたオブジェクトを変更したくない場合や、オブジェクトのディープコピーを作成したい場合はいつでも、キャッシュ実装で使用できます。

Cloner cloner=new Cloner();
XX clone = cloner.deepClone(someObjectOfTypeXX);

https://github.com/kostaskougios/cloning でチェックしてください。

17
Cojones

私は方法を見つけました、あなたはリストをシリアライズ/アンシリアライズするために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ライブラリを使ってもそれができます。

3
sagits

clone()はあなたのためにそれをしないので、あなたはArrayListを手作業で複製する必要があるでしょう(それを反復して各要素を新しいArrayListにコピーすることによって)。これは、ArrayListに含まれるオブジェクトがそれ自身をClonableに実装していない可能性があるためです。

編集:...それがまさにVarkhanのコードの動作です。

2
Stephan202

厄介な方法は反射でそれを行うことです。このようなものは私のために働いた。

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<>();
    }
}
1
milosmns

パッケージimport org.Apache.commons.lang.SerializationUtils;

SerializationUtils.clone(Object);というメソッドがあります

this.myObjectCloned = SerializationUtils.clone(this.object);
0
pacheco

他のポスターは正しいです:あなたはリストを繰り返して新しいリストにコピーする必要があります。

ただし、リスト内のオブジェクトが不変の場合は、複製する必要はありません。あなたのオブジェクトが複雑なオブジェクトグラフを持っているならば - それらも不変である必要があるでしょう。

不変性のもう1つの利点は、スレッドセーフでもあることです。

0
Fortyrunner

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

0
sonida

エンティティオブジェクトとJava.util.Listオブジェクトを複製できるライブラリを開発しました。 https://drive.google.com/open?id=0B69Sui5ah93EUTloSktFUkctN0U からjarをダウンロードして、静的メソッドcloneListObject(List list)を使用するだけです。このメソッドは、Listだけでなくすべてのエンティティ要素も複製します。

0
Eduardo de Melo

これは一般的なテンプレートタイプを使った解決策です:

public static <T> List<T> copyList(List<T> source) {
    List<T> dest = new ArrayList<T>();
    for (T item : source) { dest.add(item); }
    return dest;
}
0
Andrew Coyte

私はこのオプションをいつも使っています:

ArrayList<Dog> clonedList = new ArrayList<Dog>(name_of_arraylist_that_you_need_to_Clone);
0
besartm

あなたのオブジェクトは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()を呼び出します。

0
RN3KK Nick