Unterschied zwischen Arrays.asList (Array) und neuer ArrayList <Integer> (Arrays.asList (Array))


117

Was ist der Unterschied zwischen

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

Wo iaist ein Array von ganzen Zahlen.

Ich habe erfahren, dass einige Operationen nicht erlaubt sind list2. Wieso ist es so? Wie wird es gespeichert (Referenzen / Kopie)?

Wenn ich die Listen mische, list1wirkt sich das nicht auf das ursprüngliche Array aus, list2tut es aber . Ist aber immer noch list2etwas verwirrend.

Wie sich ArrayListdie Aktualisierung auf eine Liste von der Erstellung einer neuen Liste unterscheidetArrayList

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

2
Ich schlage vor, Sie kümmern sich um die Option von Google Guava . Lists.newArrayList(ia)erstellt eine unabhängige Kopie, genau wie die erste Option. Es ist einfach allgemeiner und besser anzusehen.
Qben

Antworten:


226
  1. Lassen Sie uns zunächst sehen, was dies bewirkt:

    Arrays.asList(ia)

    Es braucht ein Array ia und erstellt einen Wrapper, der implementiert List<Integer>, wodurch das ursprüngliche Array als Liste verfügbar wird. Es wird nichts kopiert und alles, nur ein einziges Wrapper-Objekt wird erstellt. Operationen auf dem Listen-Wrapper werden an das ursprüngliche Array weitergegeben. Dies bedeutet, dass beim Mischen des Listen-Wrappers auch das ursprüngliche Array gemischt wird. Wenn Sie ein Element überschreiben, wird es im ursprünglichen Array überschrieben usw. Natürlich sind einige ListVorgänge im Wrapper nicht zulässig, z. B. Hinzufügen oder Wenn Sie Elemente aus der Liste entfernen, können Sie nur die Elemente lesen oder überschreiben.

    Beachten Sie, dass der Listen-Wrapper nicht erweitert wird ArrayList - es handelt sich um eine andere Art von Objekt. ArrayLists haben ein eigenes internes Array, in dem sie ihre Elemente speichern und die Größe der internen Arrays usw. ändern können. Der Wrapper verfügt nicht über ein eigenes internes Array, sondern überträgt nur Operationen an das ihm zugewiesene Array.

  2. Auf der anderen Seite, wenn Sie anschließend ein neues Array als erstellen

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

    Dann erstellen Sie eine neue ArrayList, vollständige, unabhängige Kopie des Originals. Obwohl Sie hier auch den Wrapper mit erstellen Arrays.asList, wird er nur während der Erstellung des neuen verwendet ArrayListund anschließend mit Müll gesammelt. Die Struktur dieses neuen ArrayListArrays ist völlig unabhängig vom ursprünglichen Array. Es enthält dieselben Elemente (sowohl das ursprüngliche Array als auch diese neue ArrayListReferenz haben dieselben Ganzzahlen im Speicher), erstellt jedoch ein neues internes Array, das die Referenzen enthält. Wenn Sie es also mischen, Elemente hinzufügen, entfernen usw., bleibt das ursprüngliche Array unverändert.


9
@Dineshkumar Ein Wrapper ist ein Entwurfsmuster, das eine Schnittstelle für eine Klasse in eine andere Schnittstelle übersetzt. Siehe den Artikel zum Wrapper-Muster . | Wo müssen Sie upcast? Ich würde vorschlagen, List<Integer>für Ihre Variablentypen (oder Methodenargumente usw.) zu verwenden. Dadurch wird Ihr Code allgemeiner und Sie können bei Bedarf problemlos zu einer anderen ListImplementierung wechseln , ohne viel Code neu schreiben zu müssen.
Petr Pudlák

Das ist eine gute Erklärung. Um diese Frage zu erweitern, akzeptiert die Methode Arrays.asList () auch varargs. Wenn ich bestimmte Werte übergebe, z. B. zweimal: Arrays.asList (1,3,5), wird dieselbe Liste zurückgegeben?
sbsatter

27

Nun, das liegt daran, dass das ArrayListErgebnis von Arrays.asList()nicht vom Typ ist java.util.ArrayList. Arrays.asList()Erstellt einen ArrayListTyp, java.util.Arrays$ArrayListder nicht erweitert, java.util.ArrayListsondern nur erweitert wirdjava.util.AbstractList


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

In diesem Fall list1ist vom Typ ArrayList.

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

Hier wird die Liste als ListAnsicht zurückgegeben, dh es sind nur die Methoden an diese Schnittstelle angehängt. Daher sind einige Methoden nicht erlaubt list2.

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

Hier erstellen Sie eine neue ArrayList. Sie übergeben ihm einfach einen Wert im Konstruktor. Dies ist kein Beispiel für Casting. Beim Casting könnte es eher so aussehen:

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

4

Ich bin ziemlich spät hier, jedenfalls war eine Erklärung mit Dokumentenreferenzen besser für jemanden, der nach einer Antwort sucht.

  1. java.util.Arrays
  • Dies ist eine Utility-Klasse mit einer Reihe statischer Methoden, mit denen ein bestimmtes Array bearbeitet werden kann
  • asList ist eine solche statische Methode, die ein Eingabearray verwendet und ein Objekt von java.util.Arrays.ArrayList zurückgibt. Dies ist eine statische verschachtelte Klasse, die AbstractList erweitert und die List-Schnittstelle implementiert.
  • Arrays.asList (inarray) gibt also einen List-Wrapper um das Eingabearray zurück, aber dieser Wrapper ist java.util.Arrays.ArrayList und nicht java.util.ArrayList und bezieht sich auf dasselbe Array, sodass das Hinzufügen weiterer Elemente zum List-Wrapped-Array Auswirkungen haben würde Original auch und wir können auch die Länge nicht ändern.
  1. java.util.ArrayList
  • ArrayList verfügt über eine Reihe überladener Konstruktoren

    public ArrayList () - // gibt eine Arrayliste mit der Standardkapazität 10 zurück

    öffentliche ArrayList (Sammlung c)

    public ArrayList (int initialCapacity)

  • Wenn wir also das von Arrays.asList zurückgegebene Objekt, dh List (AbstractList), an den zweiten Konstruktor oben übergeben, wird ein neues dynamisches Array erstellt (diese Arraygröße nimmt zu, wenn wir mehr Elemente als seine Kapazität hinzufügen, und auch die neuen Elemente wirken sich nicht auf das ursprüngliche Array aus ) Flaches Kopieren des ursprünglichen Arrays ( Flaches Kopieren bedeutet, dass nur die Referenzen kopiert werden und kein neuer Satz derselben Objekte wie im ursprünglichen Array erstellt wird.)


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

oder

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

Die obige Anweisung fügt den Wrapper zum Eingabearray hinzu. Daher sind Methoden wie Hinzufügen und Entfernen für das Listenreferenzobjekt 'namesList' nicht anwendbar.

Wenn Sie versuchen, ein Element in das vorhandene Array / die vorhandene Liste einzufügen, erhalten Sie "Ausnahme im Thread" main "java.lang.UnsupportedOperationException".

Die obige Operation ist schreibgeschützt oder nur sichtbar.
Wir können keine Operationen zum Hinzufügen oder Entfernen im Listenobjekt ausführen. Aber

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

oder

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

In der obigen Anweisung haben Sie eine konkrete Instanz einer ArrayList-Klasse erstellt und eine Liste als Parameter übergeben.

In diesem Fall funktioniert das Hinzufügen und Entfernen von Methoden ordnungsgemäß, da beide Methoden aus der ArrayList-Klasse stammen. Daher erhalten wir hier keine UnSupportedOperationException.
Änderungen, die im Arraylist-Objekt vorgenommen wurden (Methode zum Hinzufügen oder Entfernen eines Elements in / aus einer Arraylist), werden nicht in das ursprüngliche java.util.List-Objekt übernommen.

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

Zuallererst ist die Arrays-Klasse eine Utility-Klasse, die no enthält. von Dienstprogrammmethoden für Arrays (dank der Arrays-Klasse hätten wir sonst unsere eigenen Methoden erstellen müssen, um auf Array-Objekte zu reagieren)

asList () -Methode:

  1. asListDie Methode ist eine der Dienstprogrammmethoden der ArrayKlasse. Sie ist eine statische Methode. Deshalb können wir diese Methode anhand ihres Klassennamens aufrufen (wie zArrays.asList(T...a) )
  2. Hier ist die Wendung. Bitte beachten Sie, dass diese Methode kein neues ArrayListObjekt erstellt, sondern lediglich einen Listenverweis auf ein vorhandenes ArrayObjekt zurückgibt (nach Verwendung der asListMethode werden nun zwei Verweise auf ein vorhandenes ArrayObjekt erstellt).
  3. und dies ist der Grund, warum alle Methoden, die mit einem ListObjekt arbeiten, möglicherweise NICHT mit diesem Array-Objekt unter Verwendung einer ListReferenz arbeiten, wie z. B. die ArrayGröße s ist in der Länge festgelegt. Daher können Sie Arraymit dieser ListReferenz (wie list.add(10)oder) offensichtlich keine Elemente zum Objekt hinzufügen oder daraus entfernen list.remove(10);Andernfalls wird UnsupportedOperationException ausgelöst.
  4. Jede Änderung, die Sie mithilfe der Listenreferenz vornehmen, wird beim Beenden des Arrays-Objekts berücksichtigt (wenn Sie ein vorhandenes Array-Objekt mithilfe der Listenreferenz bearbeiten).

Im ersten Fall erstellen Sie ein neues ArraylistObjekt (im zweiten Fall wird nur ein Verweis auf ein vorhandenes Array-Objekt erstellt, aber kein neues ArrayListObjekt). Jetzt gibt es zwei verschiedene Objekte, eines ist ein ArrayObjekt und ein anderes ist ein ArrayListObjekt und keine Verbindung zwischen ihnen (also Änderungen in einem Objekt wird in einem anderen Objekt nicht reflektiert / beeinflusst (dh in Fall 2 Arrayund Arraylistsind zwei verschiedene Objekte)

Fall 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));

Fall 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

Viele Leute haben die mechanischen Details bereits beantwortet, aber es ist erwähnenswert: Dies ist eine schlechte Design-Wahl von Java.

Javas asListMethode ist dokumentiert als "Gibt eine Liste mit fester Größe zurück ...". Wenn Sie das Ergebnis nehmen und die .addMethode aufrufen (sagen wir) , wird ein ausgelöst UnsupportedOperationException. Das ist unintuitives Verhalten! Wenn eine Methode angibt, dass sie a zurückgibt List, wird standardmäßig erwartet, dass sie ein Objekt zurückgibt, das die Methoden der Schnittstelle unterstützt List. Ein Entwickler sollte sich nicht merken müssen, welche der unzähligen util.ListMethoden Lists erstellt, die nicht alle ListMethoden unterstützen.

Wenn sie die Methode benannt hätten asImmutableList, wäre es sinnvoll. Oder wenn die Methode nur ein tatsächliches ListErgebnis zurückgeben würde (und das Hintergrundarray kopieren würde), wäre dies sinnvoll. Sie beschlossen, sowohl Laufzeitleistung als auch Kurznamen zu bevorzugen , auf Kosten der Verletzung sowohl des Prinzips der geringsten Überraschung als auch der guten OO-Praxis der VermeidungUnsupportedOperationException s zu .

(Auch die Designer könnten ein gemacht haben interface ImmutableList, um eine Fülle von UnsupportedOperationExceptions zu vermeiden .)


2

Beachten Sie, dass in Java 8 'ia' oben Integer [] und nicht int [] sein muss. Arrays.asList () eines int-Arrays gibt eine Liste mit einem einzelnen Element zurück. Wenn Sie das Code-Snippet von OP verwenden, wird der Compiler das Problem erkennen, aber einige Methoden (z. B. Collections.shuffle ()) werden im Stillen nicht das tun, was Sie erwarten.


1
Ich hatte dieses Compiler-Problem, als ich ArrayList <Integer> al = new ArrayList <Integer> (Arrays.asList (a)) ausführte. wo a war ein int []. Mein Al hat nur ein einziges Element, das auch beim Drucken wie Müll aussah. Was ist das für ein Element? Und wie kommt es dorthin? Ich habe dieses Problem in Java 7
Jyotsana Nandwani

@JyotsanaNandwani Bitte überprüfen Sie meine Antwort: 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()

Diese Methode gibt ihre eigene Implementierung von List zurück. Sie verwendet ein Array als Argument und erstellt darauf Methoden und Attribute, da keine Daten aus einem Array kopiert werden, sondern das ursprüngliche Array verwendet wird. Dies führt zu Änderungen im ursprünglichen Array, wenn Sie Änderungen vornehmen Liste, die von der Arrays.asList()Methode zurückgegeben wird.

andererseits.
ArrayList(Arrays.asList()); ist ein Konstruktor der ArrayListKlasse, der eine Liste als Argument verwendet und eine ArrayListvon der Liste unabhängige zurückgibt , d. h. Arrays.asList()in diesem Fall als Argument übergeben. Deshalb sehen Sie diese Ergebnisse;


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

Gibt in Zeile 2 Arrays.asList(ia)eine ListReferenz des darin definierten Objekts der inneren Klasse zurück Arrays, das ebenfalls aufgerufen wird, ArrayListaber privat ist und nur erweitert AbstractList. Dies bedeutet, dass das zurückgegebene Arrays.asList(ia)Objekt ein anderes Klassenobjekt ist als das, von dem Sie es erhaltennew ArrayList<Integer> .

Sie können einige Operationen nicht für Zeile 2 verwenden, da sich die innere private Klasse darin befindet Arrays diese Methoden nicht bereitstellt.

Schauen Sie sich diesen Link an und sehen Sie, was Sie mit der privaten inneren Klasse tun können: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/ Arrays.java # Arrays.ArrayList

Zeile 1 erstellt ein neues ArrayListObjekt, das Elemente aus dem kopiert, was Sie aus Zeile 2 erhalten. Sie können also tun, was Sie wollen, da java.util.ArrayListalle diese Methoden bereitgestellt werden.


0

Zusammenfassung des Unterschieds -

Wenn eine Liste ohne Verwendung des neuen Operators Arrays.asList () erstellt wird, wird Wrapper zurückgegeben

1. Sie können einen Add / Update-Vorgang ausführen.

2. Die im ursprünglichen Array vorgenommenen Änderungen werden auch in List übernommen und umgekehrt.


0

Als Antwort auf einige Kommentare, die Fragen zum Verhalten von Arrays.asList () seit Java 8 stellen:

    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);
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.