Java ArrayListコピー


214

私が持っているArrayList l1サイズ10. Iアサインのをl1新しいリストの参照型にl2。ウィルl1l2同じポイントArrayListオブジェクト?または、ArrayListオブジェクトのコピーが割り当てられていl2ますか?

l2参照を使用しているときに、リストオブジェクトを更新すると、l1参照タイプの変更も反映されます。

例えば:

List<Integer> l1 = new ArrayList<Integer>();
for (int i = 1; i <= 10; i++) {
    l1.add(i);
}

List l2 = l1;
l2.clear();

2つのリストオブジェクトを作成し、古いコレクションから新しいコレクションにコレクションをコピーする以外に、リストオブジェクトのコピーを新しい参照変数に割り当てる方法はありませんか?

回答:


460

はい、割り当ては(の参照)のをにコピーするだけです。どちらも同じオブジェクトを参照します。l1l2

ただし、浅いコピーを作成するのは非常に簡単です。

List<Integer> newList = new ArrayList<>(oldList);

(ちょうど一例として。)


1
arraylistの一部だけを効率的に新しいarraylistにコピーすることは可能ですか?たとえば、あるarraylistから別の新しいarraylistに位置5と10の間で要素をコピーします。私のアプリケーションでは、範囲ははるかに大きくなります。
アシュウィン2012年

1
@Ashwin:O(N)操作ですが、はい... List.subList元のリストのセクションを「表示」するために使用できます。
Jon Skeet、2012年

配列リストがネストされている場合はどうなります(ArrayList<ArrayList<Object>>)か?これは、すべての子のArrayListオブジェクトのコピーを再帰的に作成しますか?

3
@猫:いいえ...これは浅いコピーです。
Jon Skeet、

1
@ShanikaEdiriweera:ストリームを流暢に流すことができます。しかし、トリッキーな部分は、ほとんどのオブジェクトが提供しない深いコピーを作成することです。特定のケースを念頭に置いている場合は、詳細を記載した新しい質問をすることをお勧めします。
Jon Skeet、

67

14
なぜこれが望ましいのか説明してnew ArrayList<>(source);ください。
Alex

6
@atc浅いコピーを行うもう1つの方法です。新しいArrayList()の代わりに、別のアルゴリズムを使用し、ArrayListだけでなく、すべてのList実装に使用できます。つまり、すべてです:)
Sergii Zagriichuk

14
この方法は誤解を招く可能性があります!実は説明です。「1つのソースリストから宛先に要素をコピーする」とありますが、コピーされません!それらは参照されるため、オブジェクトのコピーは1つしか存在せず、それらが変更可能である場合、問題を抱えています
ACV

5
java-apiのどこにもディープクローニングはどのコレクションクラスでも行われません
Vikash

この答えはあまり意味がありません。Collections.copyはに代わるものではありませんnew ArrayList<>(source)。どのようなCollections.copy実際に行うことは、その前提としているdestination.size()として大きなとして少なくともありsource.size()、その後、範囲索引・バイ・インデックス使用してコピーするset(int,E)方法を。このメソッドは、宛先に新しい要素を追加しません。Javadocから十分に明確でない場合は、ソースコードを参照してください。
Radiodef、

35

はいl1l2同一の参照、同じオブジェクトを指します。

他のArrayListに基づいて新しいArrayListを作成する場合は、次のようにします。

List<String> l1 = new ArrayList<String>();
l1.add("Hello");
l1.add("World");
List<String> l2 = new ArrayList<String>(l1); //A new arrayList.
l2.add("Everybody");

結果はl1まだ2つの要素l2があり、3つの要素があります。


List<String> l2 = new ArrayList<String>(l1)との違いを説明していただけますList<String> l2 = l1か?
MortalMan、2015年

@MortalManの違いは、l2 = new ArrayList <String>(l1)は完全に新しいオブジェクトであり、l2を変更してもl1に影響を与えないのに対し、List <String> l2 = l1は新しいオブジェクトを作成せず、同じオブジェクトを参照するだけです。 l1としてのオブジェクトなので、この場合、l2.add( "Everybody")などの操作を実行すると、l1.size()およびl2.size()は、両方が同じオブジェクトを参照しているため、3を返します。
Alfredo Osorio 2015年

19

src ArrayListからdest Arraylistに値をコピーするもう1つの便利な方法は次のとおりです。

ArrayList<String> src = new ArrayList<String>();
src.add("test string1");
src.add("test string2");
ArrayList<String> dest= new ArrayList<String>();
dest.addAll(src);

これは値の実際のコピーであり、単なる参照のコピーではありません。


10
これが正確であるかどうかは完全にはわかりません。私のテストは反対を示しています(まだ同じオブジェクトを参照しています)
invertigo

このソリューションは、ArrayAdapterでArrayListを使用するときに私に役立ちました
albanx

1
この答えは間違っています。addAll()は、インバーティゴが言ったように参照をコピーするだけです。これはディープコピーではありません。
jk7 2018

ArrayList <String>の場合、Stringは不変であるため、この回答は受け入れられますが、OPの例であるArraList <Integer>で試してみてください。参照をコピーしているだけです。
jk7 2018

たぶん私の日ではないと思います。IntegerやLongなどのクラスも不変であることが判明したため、Harshalの回答は、ArrayList <Integer>やArrayList <String>などの単純なケースで機能します。失敗するのは、不変ではない複雑なオブジェクトの場合です。
jk7 2018

8

1つのArrayListを別のArrayListにコピーする目的で機能するメソッドaddAll()があります。

たとえば、2つの配列リストがある:sourceListtargetList、以下のコードを使用します。

targetList.addAll(sourceList);


また、参照をコピーするだけです。
Vikash

4

Javaはオブジェクトを渡さず、参照(ポインタ)をオブジェクトに渡します。つまり、l2とl1は同じオブジェクトへの2つのポインタです。

同じ内容の2つの異なるリストが必要な場合は、明示的なコピーを作成する必要があります。


3
「明示的なコピー」をどのように作成しますか?私はあなたが深いコピーについて話していると思いますか?
Cin316 2013年

1

List.copyOf ➙変更できないリスト

あなたは尋ねました:

リストのコピーを割り当てる他の方法はありませんか

Java 9は、List.ofリテラルを使用して変更不可能Listな未知の具象クラスを作成するためのメソッドをもたらしました。

LocalDate today = LocalDate.now( ZoneId.of( "Africa/Tunis" ) ) ;
List< LocalDate > dates = List.of( 
    today.minusDays( 1 ) ,  // Yesterday
    today ,                 // Today
    today.plusDays( 1 )     // Tomorrow
);

それに加えて、私たちも手に入れましたList.copyOf。このメソッドも、変更不可能Listな未知の具象クラスを返します。

List< String > colors = new ArrayList<>( 4 ) ;          // Creates a modifiable `List`. 
colors.add ( "AliceBlue" ) ;
colors.add ( "PapayaWhip" ) ;
colors.add ( "Chartreuse" ) ;
colors.add ( "DarkSlateGray" ) ;
List< String > masterColors = List.copyOf( colors ) ;   // Creates an unmodifiable `List`.

「変更不可」とは、リスト内の要素の数を意味し、要素として各スロットに保持されているオブジェクト参照が固定されます。要素を追加、削除、または置換することはできません。ただし、各要素に保持されているオブジェクト参照は、変更可能である場合とそうでない場合があります。

colors.remove( 2 ) ;          // SUCCEEDS. 
masterColors.remove( 2 ) ;    // FAIL - ERROR.

IdeOne.comでこのコードがライブで実行されるのを確認してください

date.toString():[2020-02-02、2020-02-03、2020-02-04]

colors.toString():[AliceBlue、PapayaWhip、DarkSlateGray]

masterColors.toString():[AliceBlue、PapayaWhip、Chartreuse、DarkSlateGray]

オブジェクト参照について質問しました。他の人が言ったように、1つのリストを作成して2つの参照変数(ポインター)に割り当てても、リストは1つだけです。どちらも同じリストを指しています。どちらかのポインタを使用してリストを変更した場合、メモリにはリストが1つしかないため、後で両方のポインタに変更が反映されます。

そのため、リストのコピーを作成する必要があります。そのコピーを変更できないようにするにはList.copyOf、この回答で説明されている方法を使用します。このアプローチでは、2つの別々のリストができ、それぞれに同じコンテンツオブジェクトへの参照を保持する要素があります。たとえば、Stringオブジェクトを使用して色を表す上記の例では、カラーオブジェクトはメモリのどこかに浮かんでいます。2つのリストは、同じカラーオブジェクトへのポインタを保持しています。これが図です。

ここに画像の説明を入力してください

最初のリストcolorsは変更可能です。これは、上記のコードにあるように、元の3番目の要素Chartreuse(インデックス2 =序数3)を削除した場合に、一部の要素が削除される可能性があることを意味します。そして要素を追加することができます。また、要素を変更してStringOliveDrabまたはなどの他のポイントを指すようにすることができますCornflowerBlue

対照的に、の4つの要素masterColorsは固定されています。別の色を削除したり、追加したり、置換したりする必要はありません。このList実装は変更できません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.