Arrays.asList(array)とnew ArrayList <Integer>(Arrays.asList(array))の違い


118

違いは何ですか

1.List<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia));  //copy
2.List<Integer> list2 = Arrays.asList(ia);

どこia整数の配列です。

で許可されていない操作があることを知りましたlist2。なぜそうなのですか?どのようにメモリに保存されますか(参照/コピー)?

リストをシャッフルlist1しても、元の配列には影響しませんが影響list2します。しかし、それでもlist2やや混乱しています。

ArrayListリストにアップキャストされる方法と新規作成する方法との違いArrayList

list1 differs from (1)
ArrayList<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia));

2
Google Guavaのオプションを検討することをお勧めします。Lists.newArrayList(ia)最初のオプションと同様に、独立したコピーを作成します。それは単により一般的であり、見る方が良いです。
qben 2014年

回答:


228
  1. まず、これが何をするか見てみましょう:

    Arrays.asList(ia)

    配列を取る iaをを実装するラッパーを作成しますList<Integer>。これにより、元の配列をリストとして使用できるようになります。何もコピーされず、すべて、単一のラッパーオブジェクトのみが作成されます。リストラッパーに対する操作は、元の配列に伝達されます。つまり、リストラッパーをシャッフルすると、元の配列もシャッフルされ、要素を上書きすると、元の配列で上書きされます。もちろん、List追加やリストから要素を削除すると、要素の読み取りまたは上書きのみが可能になります。

    リストラッパーは拡張しないことに注意してくださいArrayList。これは別の種類のオブジェクトです。ArrayListsには独自の内部配列があり、要素を格納し、内部配列のサイズを変更できます。ラッパーには独自の内部配列がなく、指定された配列に操作を伝達するだけです。

  2. 一方、次のように新しい配列を作成すると、

    new ArrayList<Integer>(Arrays.asList(ia))

    次にArrayList、元のの完全な独立したコピーであるnewを作成します。ここでもラッパーを使用しArrays.asListて作成しますが、新しいラッパーの構築中にのみ使用され、ArrayListその後ガベージコレクションされます。この新しい構造はArrayList、元のアレイから完全に独立しています。これには同じ要素(元の配列とこの新しいArrayList参照の両方がメモリ内の同じ整数を参照)が含まれますが、参照を保持する新しい内部配列が作成されます。そのため、シャッフル、要素の追加、削除などを行っても、元の配列は変更されません。


9
@Dineshkumarラッパーは、クラスの1つのインターフェースを別のインターフェースに変換する設計パターンです。ラッパーパターンの記事を参照しください。| どこにアップキャストする必要がありますか?List<Integer>変数の型(またはメソッドの引数など)に使用することをお勧めします。これにより、コードがより汎用的になりList、多くのコードを書き換えることなく、必要に応じて別の実装に簡単に切り替えることができます。
PetrPudlák2013年

それは良い説明です。この質問を拡張して、Arrays.asList()メソッドも可変引数を取ります。特定の値を渡すと、次のようになります:Arrays.asList(1,3,5)を2回実行すると、同じリストが返されますか?
sbsatter

27

まあこれは、ArrayList結果Arrays.asList()がタイプではないためjava.util.ArrayListです。拡張しないで拡張するだけのタイプのをArrays.asList()作成しますArrayListjava.util.Arrays$ArrayListjava.util.ArrayListjava.util.AbstractList


9
List<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia));  //copy

この場合、list1タイプはArrayListです。

List<Integer> list2 = Arrays.asList(ia);

ここでは、リストはListビューとして返されます。つまり、そのインターフェースにアタッチされているメソッドのみが含まれています。したがって、一部のメソッドがで許可されないのはなぜですかlist2

ArrayList<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia));

ここでは、新しいを作成していますArrayList。コンストラクタに値を渡すだけです。これはキャストの例ではありません。キャストでは、次のようになります。

ArrayList list1 = (ArrayList)Arrays.asList(ia);

4

私はここでかなり遅れています。とにかく、ドキュメント参照の説明は、答えを探している人にとってはより良いと感じました。

  1. java.util.Arrays
  • これは、指定された配列を操作するための一連の静的メソッドを持つユーティリティクラスです。
  • asListは、入力配列を受け取り、Listインターフェースを実装するAbstractListを拡張する静的なネストされたクラスであるjava.util.Arrays.ArrayListのオブジェクトを返す、そのような静的メソッドの1つです。
  • したがって、Arrays.asList(inarray)は入力配列のリストラッパーを返しますが、このラッパーはjava.util.Arrays.ArrayListでjava.util.ArrayListではなく、同じ配列を参照しているため、Listラップ配列に要素を追加すると影響がありますオリジナルのものも、長さを変更することはできません。
  1. java.util.ArrayList
  • ArrayListにはオーバーロードされたコンストラクターがたくさんあります

    public ArrayList()-//デフォルトの容量10でarraylistを返します

    public ArrayList(Collection c)

    public ArrayList(int initialCapacity)

  • したがって、Arrays.asListで返されたオブジェクト、つまりList(AbstractList)を上記の2番目のコンストラクタに渡すと、新しい動的配列が作成されます(この配列のサイズは、容量より多くの要素を追加すると増加し、新しい要素は元の配列に影響しません) )元の配列の浅いコピー浅いコピーとは、参照のみをコピーし、元の配列と同じオブジェクトの新しいセットを作成しないことを意味します)


4
String names[] = new String[]{"Avinash","Amol","John","Peter"};
java.util.List<String> namesList = Arrays.asList(names);

または

String names[] = new String[]{"Avinash","Amol","John","Peter"};
java.util.List<String> temp = Arrays.asList(names);         

上記のステートメントは、入力配列にラッパーを追加します。そのため、add&removeなどのメソッドは、リスト参照オブジェクト 'namesList'には適用されません。

既存の配列/リストに要素を追加しようとすると、「スレッド "main"で例外 "java.lang.UnsupportedOperationException"が発生します。

上記の操作は読み取り専用または表示専用です。
リストオブジェクトで追加または削除操作を実行できません。だが

String names[] = new String[]{"Avinash","Amol","John","Peter"};
java.util.ArrayList<String> list1 = new ArrayList<>(Arrays.asList(names));

または

String names[] = new String[]{"Avinash","Amol","John","Peter"};
java.util.List<String> listObject = Arrays.asList(names);
java.util.ArrayList<String> list1 = new ArrayList<>(listObject);

上記のステートメントでは、ArrayListクラスの具象インスタンスを作成し、パラメーターとしてリストを渡しました。

この場合、両方のメソッドがArrayListクラスからのものであるため、メソッドadd&removeは正しく機能します。そのため、ここではUnSupportedOperationExceptionを取得しません。
Arraylistオブジェクトで行われた変更(arraylistの要素を追加または削除するメソッド)は、元のjava.util.Listオブジェクトに反映されません。

String names[] = new String[] {
    "Avinash",
    "Amol",
    "John",
    "Peter"
};

java.util.List < String > listObject = Arrays.asList(names);
java.util.ArrayList < String > list1 = new ArrayList < > (listObject);
for (String string: list1) {
    System.out.print("   " + string);
}
list1.add("Alex"); //Added without any exception
list1.remove("Avinash"); //Added without any exception will not make any changes in original list in this case temp object.


for (String string: list1) {
    System.out.print("   " + string);
}
String existingNames[] = new String[] {
    "Avinash",
    "Amol",
    "John",
    "Peter"
};
java.util.List < String > namesList = Arrays.asList(names);
namesList.add("Bob"); // UnsupportedOperationException occur
namesList.remove("Avinash"); //UnsupportedOperationException

3

まず、Arraysクラスは、何も含まないユーティリティクラスです。配列を操作するユーティリティメソッドの一覧(Arraysクラスのおかげでそれ以外の場合は、Arrayオブジェクトを操作する独自のメソッドを作成する必要がありました)

asList()メソッド:

  1. asListmethodはArrayclass のユーティリティメソッドの1つであり、静的メソッドであるため、このメソッドをクラス名(Arrays.asList(T...a))で
  2. これがひねりです。このメソッドは新しいArrayListオブジェクトを作成せず、既存のArrayオブジェクトへのList参照を返すだけです(asListメソッドを使用した後、既存のオブジェクトへの2つの参照)Arrayオブジェクトが作成されます)
  3. これが理由です。たとえば、Listオブジェクトを操作するすべてのメソッドは、List参照を使用してこのArrayオブジェクトで機能しない可能性があります。たとえば、Arraysサイズは固定長であるため、ArrayこのList参照を使用してオブジェクトに要素を追加または削除することはできません(list.add(10)またはlist.remove(10);それ以外の場合はUnsupportedOperationExceptionをスローします)
  4. リスト参照を使用して行っている変更は、既存Arrayのsオブジェクトに反映されます(リスト参照を使用して既存のArrayオブジェクトを操作しているため)

最初のケースでは、新しいArraylistオブジェクトを作成しています(2番目のケースでは、既存のArrayオブジェクトへの参照のみが作成され、新しいArrayListオブジェクトは作成されません)。これで、Arrayオブジェクトとオブジェクトの2つの異なるオブジェクトがありArrayList、それらの間の接続はありません(そのため、変更あるオブジェクトでは別のオブジェクトに反映/影響されません(つまり、ケース2 ArrayArraylist2つの異なるオブジェクトです)

ケース1:

Integer [] ia = {1,2,3,4};
System.out.println("Array : "+Arrays.toString(ia));
List<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia));  // new ArrayList object is created , no connection between existing Array Object
list1.add(5);
list1.add(6);
list1.remove(0);
list1.remove(0);
System.out.println("list1 : "+list1);
System.out.println("Array : "+Arrays.toString(ia));

ケース2:

Integer [] ia = {1,2,3,4};
System.out.println("Array : "+Arrays.toString(ia));
List<Integer> list2 = Arrays.asList(ia); // creates only a (new ) List reference to existing Array object (and NOT a new ArrayList Object)
//  list2.add(5); //  it will throw java.lang.UnsupportedOperationException - invalid operation (as Array size is fixed)
list2.set(0,10);  // making changes in existing Array object using List reference - valid 
list2.set(1,11); 
ia[2]=12;     // making changes in existing Array object using Array reference - valid
System.out.println("list2 : "+list2);
System.out.println("Array : "+Arrays.toString(ia));

3

多くの人がすでに機械的な詳細に回答していますが、注目に値します。これは、Javaによる設計の選択としては不適切です。

JavaのasListメソッドは、「固定サイズのリストを返す...」として文書化されています。その結果を受け取って(たとえば).addメソッドを呼び出すと、がスローされますUnsupportedOperationException。これは直感に反する動作です!メソッドがを返すと言った場合、List標準の期待は、それがインターフェイスのメソッドをサポートするオブジェクトを返すことListです。開発者は、実際にすべてのメソッドをサポートしていないumpteen メソッドを作成するメソッドを覚えおく必要はありません。util.ListListList

彼らがメソッドasImmutableListに名前を付けていれば、それは理にかなっています。または、メソッドに実際の値を返すList(そしてバッキング配列をコピーする)だけの場合、それは理にかなっています。彼らは、ランタイムパフォーマンス短い名前の両方を優先することを決定しましたが、最小サプライズの原則と回避するという優れたOOプラクティスの両方に違反します。UnsupportedOperationException sます。

(また、デザイナーinterface ImmutableListUnsupportedOperationExceptionsを大量に作成することを避けるためにを作成した可能性があります。)


2

Java 8では、上記の「ia」はInteger []であり、int []ではないことに注意してください。int配列のArrays.asList()は、単一の要素を持つリストを返します。OPのコードスニペットを使用すると、コンパイラーが問題をキャッチしますが、一部のメソッド(たとえば、Collections.shuffle())は意図したとおりに何もせずに失敗します。


1
ArrayList <Integer> al = new ArrayList <Integer>(Arrays.asList(a));を実行したときに、このコンパイラの問題に直面しました。ここで、aはint []でした。私のalは、印刷されたときにゴミのように見える単一の要素も取得しました。その要素は何ですか?そして、どうやってそこに来るのですか?私はJava 7でこの問題に直面しました
Jyotsana Nandwani 2017

@JyotsanaNandwani Plsが私の答えを確認します:stackoverflow.com/a/54105519/1163607
NINCOMPOOP

1
package com.copy;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class CopyArray {

    public static void main(String[] args) {
        List<Integer> list1, list2 = null;
        Integer[] intarr = { 3, 4, 2, 1 };
        list1 = new ArrayList<Integer>(Arrays.asList(intarr));
        list1.add(30);
        list2 = Arrays.asList(intarr);
        // list2.add(40); Here, we can't modify the existing list,because it's a wrapper
        System.out.println("List1");
        Iterator<Integer> itr1 = list1.iterator();
        while (itr1.hasNext()) {
            System.out.println(itr1.next());
        }
        System.out.println("List2");
        Iterator<Integer> itr2 = list2.iterator();
        while (itr2.hasNext()) {
            System.out.println(itr2.next());
        }
    }
}

1

Arrays.asList()

このメソッドは、Listの独自の実装を返します。配列から引数を取り、その上にメソッドと属性を構築します。これは、配列からデータをコピーするのではなく、元の配列を使用するため、変更すると元の配列が変更されるためです。Arrays.asList()メソッドによって返されるリスト。

一方。引数としてリストを取り、リストに依存しないを返すクラスの
ArrayList(Arrays.asList()); コンストラクタです。この場合、引数として渡されます。そのため、これらの結果が表示されます。ArrayListArrayListArrays.asList()


0
1.List<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia));  //copy
2.List<Integer> list2 = Arrays.asList(ia);

2行目でArrays.asList(ia)は、ListArraysで定義されている内部クラスオブジェクトの参照を返します。これは、呼び出されますArrayListが、プライベートであり、拡張のみAbstractListです。つまり、返されるものArrays.asList(ia)は、取得したものとは異なるクラスオブジェクトです。new ArrayList<Integer>

内のプライベートクラスが2であるため、一部の操作を2行目に使用できません Arraysはこれらのメソッドを提供しない。

このリンクを見て、プライベート内部クラスで何ができるかを確認してくださいhttp : //grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/ Arrays.java#Arrays.ArrayList

1行目は、ArrayList2行目から取得した要素から要素をコピーする新しいオブジェクトを作成します。したがってjava.util.ArrayList、これらのメソッドがすべて提供されているので、好きなことを実行できます。


0

違いの要約-

新しい演算子Arrays.asList()メソッドを使用せずにリストを作成すると、Wrapperが返されます。

1.追加/更新操作を実行できます。

2.元の配列で行われた変更はリストにも反映され、その逆も同様です。


0

Java 8以降のArrays.asList()の動作について質問するコメントへの回答:

    int[] arr1 = {1,2,3};
    /* 
       Arrays are objects in Java, internally int[] will be represented by 
       an Integer Array object which when printed on console shall output
       a pattern such as 
       [I@address for 1-dim int array,
       [[I@address for 2-dim int array, 
       [[F@address for 2-dim float array etc. 
   */
    System.out.println(Arrays.asList(arr1)); 

    /* 
       The line below results in Compile time error as Arrays.asList(int[] array)
       returns List<int[]>. The returned list contains only one element 
       and that is the int[] {1,2,3} 
    */
    // List<Integer> list1 = Arrays.asList(arr1);

    /* 
       Arrays.asList(arr1) is  Arrays$ArrayList object whose only element is int[] array
       so the line below prints [[I@...], where [I@... is the array object.
    */
    System.out.println(Arrays.asList(arr1)); 

    /* 
     This prints [I@..., the actual array object stored as single element 
     in the Arrays$ArrayList object. 
    */
    System.out.println(Arrays.asList(arr1).get(0));

    // prints the contents of array [1,2,3]
    System.out.println(Arrays.toString(Arrays.asList(arr1).get(0)));

    Integer[] arr2 = {1,2,3};
    /* 
     Arrays.asList(arr) is  Arrays$ArrayList object which is 
     a wrapper list object containing three elements 1,2,3.
     Technically, it is pointing to the original Integer[] array 
    */
    List<Integer> list2 = Arrays.asList(arr2);

    // prints the contents of list [1,2,3]
    System.out.println(list2);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.