Differenza tra Arrays.asList (array) e new ArrayList <Integer> (Arrays.asList (array))


119

Qual è la differenza tra

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

dove iaè matrice di numeri interi.

Sono venuto a sapere che alcune operazioni non sono consentite list2. perché è così? come viene immagazzinato in memoria (riferimenti / copia)?

Quando mischio gli elenchi, list1non influisce sull'array originale ma lo list2fa. Ma list2è ancora un po 'confuso.

In che modo ArrayListl'upcasting nell'elenco differisce dalla creazione di nuoviArrayList

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

2
Ti suggerisco di occuparti dell'opzione di Google Guava . Lists.newArrayList(ia)crea una copia indipendente, proprio come la prima opzione. È semplicemente più generale e migliore da guardare.
qben

Risposte:


228
  1. Per prima cosa, vediamo cosa fa:

    Arrays.asList(ia)

    Prende un array iae crea un wrapper che implementa List<Integer>, che rende disponibile l'array originale come elenco. Niente viene copiato e tutto, viene creato solo un singolo oggetto wrapper. Le operazioni sul wrapper dell'elenco vengono propagate all'array originale. Ciò significa che se mescoli il wrapper della lista, anche l'array originale viene mescolato, se sovrascrivi un elemento, viene sovrascritto nell'array originale, ecc. Ovviamente, alcune Listoperazioni non sono consentite sul wrapper, come l'aggiunta o rimuovendo elementi dall'elenco, è possibile solo leggere o sovrascrivere gli elementi.

    Nota che il wrapper della lista non si estende ArrayList: è un diverso tipo di oggetto. ArrayListhanno il proprio array interno, in cui memorizzano i propri elementi, e sono in grado di ridimensionare gli array interni, ecc. Il wrapper non ha il proprio array interno, propaga solo le operazioni all'array datogli.

  2. D'altra parte, se successivamente crei un nuovo array come

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

    quindi ne crei una nuova ArrayList, che è una copia completa e indipendente dell'originale. Anche se qui si crea anche il wrapper Arrays.asList, viene utilizzato solo durante la costruzione del nuovo ArrayListe successivamente viene raccolto dai rifiuti. La struttura di questo nuovo ArrayListè completamente indipendente dall'array originale. Contiene gli stessi elementi (sia l'array originale che questo nuovo ArrayListriferimento agli stessi numeri interi in memoria), ma crea un nuovo array interno, che contiene i riferimenti. Quindi, quando lo mischi, aggiungi, rimuovi elementi ecc., L'array originale rimane invariato.


9
@Dineshkumar Un wrapper è un modello di progettazione che traduce un'interfaccia per una classe in un'altra interfaccia. Vedi l' articolo sul pattern wrapper . | Dove devi eseguire l'upcast? Suggerirei di utilizzare List<Integer>per i tipi di variabili (o argomenti del metodo, ecc.). Questo rende il tuo codice più generico e puoi passare facilmente a un'altra Listimplementazione secondo necessità, senza dover riscrivere molto codice.
Petr Pudlák

Questa è una buona spiegazione. Estendendo questa domanda, il metodo Arrays.asList () accetta anche varargs. Se passo valori specifici, diciamo che faccio: Arrays.asList (1,3,5) due volte, restituirà lo stesso elenco?
sbsatter

27

Ebbene questo perché ArrayListrisultante da Arrays.asList()non è del tipo java.util.ArrayList. Arrays.asList()crea un ArrayListtipo java.util.Arrays$ArrayListche non si estende java.util.ArrayListma solo si estendejava.util.AbstractList


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

In questo caso, list1è di tipo ArrayList.

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

Qui, l'elenco viene restituito come una Listvista, il che significa che ha solo i metodi collegati a quell'interfaccia. Ecco perché alcuni metodi non sono consentiti list2.

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

Qui, stai creando un nuovo file ArrayList. Stai semplicemente passando un valore nel costruttore. Questo non è un esempio di casting. Nel casting, potrebbe essere più simile a questo:

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

4

Sono abbastanza in ritardo qui, comunque ho ritenuto che una spiegazione con riferimenti a documenti sarebbe stata migliore per qualcuno in cerca di risposta.

  1. java.util.Arrays
  • Questa è una classe di utilità con un sacco di metodi statici per operare su un dato array
  • asList è uno di questi metodi statici che accetta array di input e restituisce un oggetto di java.util.Arrays.ArrayList che è una classe annidata statica che estende AbstractList che a sua volta implementa l'interfaccia List.
  • Quindi Arrays.asList (inarray) restituisce un wrapper List attorno all'array di input ma questo wrapper è java.util.Arrays.ArrayList e non java.util.ArrayList e si riferisce allo stesso array, quindi l'aggiunta di più elementi all'array avvolto in List avrebbe effetto anche quello originale e inoltre non possiamo cambiare la lunghezza.
  1. java.util.ArrayList
  • ArrayList ha un sacco di costruttori sovraccarichi

    public ArrayList () - // restituisce arraylist con capacità predefinita 10

    public ArrayList (Collezione c)

    public ArrayList (int initialCapacity)

  • Quindi, quando passiamo l'oggetto restituito da Arrays.asList, ad esempio List (AbstractList) al secondo costruttore sopra, creerà un nuovo array dinamico (la dimensione di questo array aumenta quando aggiungiamo più elementi della sua capacità e anche i nuovi elementi non influenzeranno l'array originale ) copia superficiale dell'array originale ( copia superficiale significa che copia solo sui riferimenti e non crea un nuovo set di oggetti come nell'array originale)


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

o

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

L'istruzione Above aggiunge il wrapper all'array di input. Quindi i metodi come aggiungi e rimuovi non saranno applicabili all'oggetto di riferimento della lista 'namesList'.

Se provi ad aggiungere un elemento nella matrice / elenco esistente, otterrai "Eccezione nel thread" principale "java.lang.UnsupportedOperationException".

L'operazione di cui sopra è di sola lettura o di sola visualizzazione.
Non è possibile eseguire operazioni di aggiunta o rimozione nell'oggetto elenco. Ma

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

o

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

Nella dichiarazione precedente hai creato un'istanza concreta di una classe ArrayList e passato un elenco come parametro.

In questo caso, il metodo aggiungi e rimuovi funzionerà correttamente poiché entrambi i metodi provengono dalla classe ArrayList, quindi qui non avremo alcuna UnSupportedOperationException.
Le modifiche apportate all'oggetto Arraylist (metodo di aggiunta o rimozione di un elemento in / da un arraylist) non verranno riflesse nell'oggetto java.util.List originale.

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

Prima di tutto la classe Arrays è una classe di utilità che contiene no. di metodi di utilità per operare su Array (grazie alla classe Arrays altrimenti avremmo avuto bisogno di creare i nostri metodi per agire sugli oggetti Array)

metodo asList ():

  1. asListmetodo è uno dei metodi di utilità della Arrayclasse, è questo è il motivo per cui metodo statico Possiamo chiamare questo metodo con il nome di classe (comeArrays.asList(T...a) )
  2. Ora ecco la svolta, tieni presente che questo metodo non crea un nuovo ArrayListoggetto, restituisce solo un riferimento List a un Arrayoggetto esistente (quindi ora dopo aver usato il asListmetodo, Arrayvengono creati due riferimenti all'oggetto esistente )
  3. e questo è il motivo, tutti i metodi che operano su un Listoggetto, potrebbero NON funzionare su questo oggetto Array usando Listriferimenti come, ad esempio, Arrayla dimensione di s è fissa in lunghezza, quindi ovviamente non puoi aggiungere o rimuovere elementi Arraydall'oggetto usando questo Listriferimento (come list.add(10)o list.remove(10);altrimenti lancerà UnsupportedOperationException)
  4. qualsiasi modifica che stai facendo utilizzando il riferimento elenco si rifletterà Arraynell'oggetto s uscente (mentre stai operando su un oggetto Array esistente utilizzando il riferimento elenco)

Nel primo caso stai creando un nuovo Arraylistoggetto (nel secondo caso viene creato solo il riferimento all'oggetto Array esistente ma non un nuovo ArrayListoggetto), quindi ora ci sono due oggetti diversi uno è Arrayoggetto e un altro è ArrayListoggetto e nessuna connessione tra di loro (quindi cambia in un oggetto non verrà riflesso / influenzato in un altro oggetto (cioè nel caso 2 Arraye Arraylistsono due oggetti diversi)

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

caso 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

Molte persone hanno già risposto ai dettagli meccanici, ma vale la pena notare: questa è una scelta di design scadente, da parte di Java.

Il asListmetodo di Java è documentato come "Restituisce un elenco di dimensioni fisse ...". Se prendi il suo risultato e chiami (diciamo) il .addmetodo, genera un UnsupportedOperationException. Questo è un comportamento non intuitivo! Se un metodo dice che restituisce a List, l'aspettativa standard è che restituisca un oggetto che supporta i metodi di interfaccia List. Uno sviluppatore non dovrebbe dover memorizzare quale degli innumerevoli util.Listmetodi crea messaggi Listche in realtà non supportano tutti i Listmetodi.

Se avessero nominato il metodo asImmutableList, avrebbe senso. Oppure, se il metodo restituisse un valore reale List(e copiasse l'array di supporto), avrebbe senso. Hanno deciso di privilegiare sia le prestazioni di runtime che i nomi brevi, a scapito di violare sia il Principio di Minima Sorpresa che la buona pratica OO di evitareUnsupportedOperationException i messaggi .

(Inoltre, i progettisti potrebbero aver realizzato un interface ImmutableList, per evitare una pletora di UnsupportedOperationExceptions.)


2

Notare che, in Java 8, "ia" sopra deve essere Integer [] e non int []. Arrays.asList () di un array int restituisce un elenco con un singolo elemento. Quando si utilizza lo snippet di codice di OP, il compilatore rileverà il problema, ma alcuni metodi (ad es. Collections.shuffle ()) non riusciranno silenziosamente a fare ciò che ti aspetti.


1
Ho affrontato questo problema del compilatore quando ho fatto ArrayList <Integer> al = new ArrayList <Integer> (Arrays.asList (a)); dove a era un int []. Il mio ha solo un singolo elemento che anche quando stampato sembrava spazzatura. Cos'è quell'elemento? E come mai ci sei arrivato? Ho affrontato questo problema in Java 7
Jyotsana Nandwani il

@JyotsanaNandwani Pls controllare la mia risposta: 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()

questo metodo restituisce la propria implementazione di List Prende un array come argomento e crea metodi e attributi sopra di esso, poiché non sta copiando alcun dato da un array ma utilizzando l'array originale ciò causa l'alterazione dell'array originale quando si modifica elenco restituito dal Arrays.asList()metodo.

d'altro canto.
ArrayList(Arrays.asList()); è un costruttore di ArrayListclassi che accetta una lista come argomento e restituisce una ArrayListche è indipendente dalla lista cioè. Arrays.asList()in questo caso passato come argomento. ecco perché vedi questi risultati;


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

Nella riga 2, Arrays.asList(ia)restituisce un Listriferimento all'oggetto della classe interna definito all'interno Arrays, che viene anche chiamato ArrayListma è privato e si estende solo AbstractList. Ciò significa che ciò che viene restituito Arrays.asList(ia)è un oggetto di classe diverso da ciò da cui si ottienenew ArrayList<Integer> .

Non è possibile utilizzare alcune operazioni sulla riga 2 perché la classe privata interna all'interno di Arrays non fornisce tali metodi.

Dai un'occhiata a questo link e guarda cosa puoi fare con la classe interna privata: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/ Arrays.java # Arrays.ArrayList

La riga 1 crea un nuovo ArrayListoggetto copiando elementi da ciò che ottieni dalla riga 2. Quindi puoi fare quello che vuoi poiché java.util.ArrayListfornisce tutti questi metodi.


0

Riepilogo della differenza -

quando l'elenco viene creato senza utilizzare il nuovo operatore Arrays.asList (), restituisce Wrapper che significa

1. è possibile eseguire l'operazione di aggiunta / aggiornamento.

2. le modifiche apportate nell'array originale si rifletteranno anche su List e viceversa.


0

In risposta ad alcuni commenti che pongono domande sul comportamento di Arrays.asList () a partire da Java 8:

    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);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.