Copia Java ArrayList


214

Ho una ArrayList l1dimensione 10. Assegno l1al nuovo tipo di riferimento elenco l2. Will l1e l2punta allo stesso ArrayListoggetto? Oppure viene ArrayListassegnata una copia dell'oggetto l2?

Quando utilizzo il l2riferimento, se aggiorno l'oggetto elenco, riflette anche le modifiche nel l1tipo di riferimento.

Per esempio:

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

List l2 = l1;
l2.clear();

Non c'è altro modo di assegnare una copia di un oggetto elenco a una nuova variabile di riferimento, oltre a creare 2 oggetti elenco e fare una copia su raccolte dal vecchio al nuovo?

Risposte:


460

Sì, l'assegnazione copierà semplicemente il valore di l1(che è un riferimento) in l2. Si riferiranno entrambi allo stesso oggetto.

La creazione di una copia superficiale è piuttosto semplice:

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

(Proprio come un esempio.)


1
È possibile copiare solo una parte di un arraylist in un nuovo arraylist, in modo efficiente. ad esempio: copiare elementi tra le posizioni 5 e 10 da un arraylist a un altro nuovo arraylist. Nella mia applicazione la gamma sarebbe molto più grande.
Ashwin,

1
@Ashwin: Beh, è ​​un'operazione O (N), ma sì ... puoi usare List.subListper ottenere una "vista" su una sezione dell'elenco originale.
Jon Skeet,

cosa succede se gli elenchi di array sono nidificati (ArrayList<ArrayList<Object>>)? questo creerebbe in modo ricorsivo copie di tutti gli oggetti ArrayList figlio?
Gatto

3
@Cat: No ... Questa è solo una copia superficiale.
Jon Skeet,

1
@ShanikaEdiriweera: potresti farlo in modo fluente con i flussi, sì. Ma la parte difficile è creare una copia profonda, che la maggior parte degli oggetti non fornirà. Se hai in mente un caso specifico, ti suggerisco di porre una nuova domanda con i dettagli.
Jon Skeet,

67

14
new ArrayList<>(source);Vuoi spiegare perché questo potrebbe essere preferibile a ?
Alex

6
@atc è un altro modo per fare una copia superficiale, invece del nuovo ArrayList () è usato un altro algoritmo e può essere usato per qualsiasi implementazione di Elenco, non solo per un ArrayList, questo è tutto :)
Sergii Zagriichuk

14
Questo metodo è molto fuorviante! In realtà, è la descrizione. Dice: "copia gli elementi da un elenco di sorgenti nella destinazione", ma non vengono copiati! Sono referenziati quindi ci sarà 1 sola copia degli oggetti e se sono mutabili, sei nei guai
ACV

5
da nessuna classe di raccolta viene effettuata alcuna clonazione profonda java-api
Vikash,

Questa risposta non ha molto senso. Collections.copynon è affatto un'alternativa a new ArrayList<>(source). Ciò che Collections.copyeffettivamente fa è assumere che destination.size()sia almeno grande quanto source.size(), quindi copiare l'intervallo indice per indice usando il set(int,E)metodo. Il metodo non aggiunge nuovi elementi alla destinazione. Fare riferimento al codice sorgente se non è abbastanza chiaro da Javadoc.
Radiodef,

35

l1e l2punterà allo stesso riferimento, stesso oggetto.

Se si desidera creare una nuova ArrayList basata sull'altra ArrayList, procedere come segue:

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

Il risultato sarà l1avrà ancora 2 elementi e l2avrà 3 elementi.


Puoi spiegare la differenza tra List<String> l2 = new ArrayList<String>(l1)e List<String> l2 = l1?
MortalMan,

@MortalMan la differenza è che l2 = new ArrayList <String> (l1) è un oggetto completamente nuovo e la modifica di l2 non influisce su l1, mentre List <String> l2 = l1 non stai creando un nuovo oggetto ma semplicemente facendo riferimento allo stesso oggetto come l1, quindi in questo caso un'operazione come l2.add ("Everybody"), l1.size () e l2.size () restituirà 3 perché entrambi fanno riferimento allo stesso oggetto.
Alfredo Osorio,

19

Un altro modo conveniente per copiare i valori da src ArrayList a dest Arraylist è il seguente:

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

Questa è la copia effettiva dei valori e non solo la copia di riferimento.


10
non sono del tutto sicuro che questo sia accurato. il mio test mostra il contrario (facendo ancora riferimento allo stesso oggetto)
invertigo

questa soluzione ha funzionato per me usando ArrayList con ArrayAdapter
albanx il

1
Questa risposta è sbagliata addAll () copia solo i riferimenti come ha detto invertigo. Questa non è una copia profonda.
jk7,

Per un ArrayList <String> questa risposta è accettabile perché String è immutabile, ma provalo con l'esempio dell'OP, un ArraList <Integer>, e vedrai che sta solo copiando i riferimenti.
jk7,

Solo che non è il mio giorno immagino. Si scopre che classi come Integer e Long sono anche immutabili, quindi la risposta di Harshal funziona per casi semplici come ArrayList <Integer> e ArrayList <String>. Dove non riesce è per oggetti complessi che non sono immutabili.
jk7,

8

Esiste un metodo addAll () che servirà allo scopo di copiare una ArrayList in un'altra.

Ad esempio, hai due elenchi di array: sourceList e targetList , usa il codice seguente.

targetList.addAll (listaOrigine);


copia anche solo riferimenti.
Vikash,

4

Java non passa oggetti, passa riferimenti (puntatori) agli oggetti. Quindi sì, l2 e l1 sono due puntatori allo stesso oggetto.

Devi fare una copia esplicita se hai bisogno di due diversi elenchi con lo stesso contenuto.


3
Come si fa a "una copia esplicita"? Suppongo che stai parlando di una copia profonda?
Cin316,

1

List.copyOf ➙ elenco non modificabile

Hai chiesto:

Non esiste altro modo per assegnare una copia di un elenco

Java 9 ha portato i List.ofmetodi per usare i letterali per creare una Listclasse concreta non modificabile di sconosciuta.

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

Insieme a quello abbiamo anche ottenuto List.copyOf. Anche questo metodo restituisce un non modificabile Listdi classe concreta sconosciuta.

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`.

Per "non modificabile" intendiamo il numero di elementi nell'elenco e il riferimento all'oggetto contenuto in ogni slot come elemento è fisso. Non è possibile aggiungere, eliminare o sostituire elementi. Ma il referente oggetto contenuto in ciascun elemento può o meno essere mutabile .

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

Vedi questo codice eseguito dal vivo su IdeOne.com .

Date.toString (): [2020-02-02, 2020-02-03, 2020-02-04]

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

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

Hai chiesto informazioni sui riferimenti agli oggetti. Come altri hanno detto, se crei un elenco e lo assegni a due variabili di riferimento (puntatori), hai ancora un solo elenco. Entrambi indicano lo stesso elenco. Se si utilizza uno dei due puntatori per modificare l'elenco, entrambi i puntatori vedranno in seguito le modifiche, poiché esiste un solo elenco in memoria.

Quindi devi fare una copia dell'elenco. Se vuoi che quella copia non sia modificabile, usa il List.copyOfmetodo come discusso in questa risposta. In questo approccio, si finisce con due elenchi separati, ciascuno con elementi che contengono un riferimento agli stessi oggetti contenuto. Ad esempio, nel nostro esempio sopra che utilizza Stringoggetti per rappresentare i colori, gli oggetti colorati fluttuano nella memoria da qualche parte. I due elenchi contengono puntatori agli oggetti dello stesso colore. Ecco un diagramma.

inserisci qui la descrizione dell'immagine

Il primo elenco colorsè modificabile. Ciò significa che alcuni elementi potrebbero essere rimossi come visto nel codice sopra, dove abbiamo rimosso il 3 ° elemento originale Chartreuse(indice di 2 = ordinale 3). E gli elementi possono essere aggiunti. E gli elementi possono essere cambiati per puntare ad altri Stringcome OliveDraboCornflowerBlue .

Al contrario, i quattro elementi di masterColorssono fissi. Nessuna rimozione, nessuna aggiunta e nessuna sostituzione di un altro colore. Tale Listimplementazione è immodificabile.

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.