Kopia ArrayList Java

214

Mam ArrayList l1rozmiar 10. Przypisuję l1nowy typ odwołania do listy l2. Will l1i l2punkt do samego ArrayListobiektu? A może kopia ArrayListobiektu jest przypisana l2?

Gdy korzystam z l2odwołania, jeśli zaktualizuję obiekt listy, odzwierciedla również zmiany w l1typie odwołania.

Na przykład:

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

List l2 = l1;
l2.clear();

Czy nie ma innego sposobu przypisania kopii obiektu listy do nowej zmiennej referencyjnej, oprócz utworzenia 2 obiektów listy i wykonania kopii na kolekcjach od starych do nowych?

użytkownik309281
źródło

Odpowiedzi:

460

Tak, cesja będzie po prostu skopiować wartość z l1(co jest nawiązaniem) do l2. Oba będą odnosić się do tego samego obiektu.

Tworzenie płytkiej kopii jest jednak dość łatwe:

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

(Tylko jako jeden przykład.)

Jon Skeet
źródło
1
Czy możliwe jest skopiowanie tylko części arraylisty do nowej arraylisty, w sposób wydajny. na przykład: skopiuj elementy między pozycją 5 a 10 z jednej listy zestawów do innej nowej listy. W mojej aplikacji zasięg byłby znacznie większy.
Ashwin
1
@Ashwin: Cóż, jest to operacja O (N), ale tak ... możesz użyć, List.subListaby uzyskać „widok” na sekcję oryginalnej listy.
Jon Skeet
co jeśli zagnieżdżone są listy tablic (ArrayList<ArrayList<Object>>)? czy rekurencyjnie utworzy to kopie wszystkich potomnych obiektów ArrayList?
Kot
3
@Cat: Nie ... To tylko płytka kopia.
Jon Skeet
1
@ShanikaEdiriweera: Tak, możesz to robić płynnie dzięki strumieniom. Ale trudną częścią jest stworzenie głębokiej kopii, której większość obiektów nie zapewni. Jeśli masz na myśli konkretny przypadek, proponuję zadać nowe pytanie ze szczegółami.
Jon Skeet
67

Spróbuj użyć Collections.copy(destination, source);

Sergii Zagriichuk
źródło
14
Chcesz wyjaśnić, dlaczego może to być lepsze new ArrayList<>(source);?
Alex
6
@atc to jeszcze jeden sposób na płytkie kopiowanie, zamiast nowej ArrayList () zastosowano inny algorytm i można go użyć do dowolnej implementacji listy, nie tylko do ArrayList, to wszystko :)
Sergii Zagriichuk
14
Ta metoda jest bardzo myląca! W rzeczywistości jest to opis. Mówi: „kopiuje elementy z jednej listy źródeł do miejsca docelowego”, ale nie są one kopiowane! Są one przywoływane, więc będzie tylko 1 kopia obiektów, a jeśli można je modyfikować, masz kłopoty
ACV
5
nigdzie w java-api głębokie klonowanie nie jest wykonywane przez żadną klasę kolekcji
Vikash
Ta odpowiedź nie ma większego sensu. Collections.copywcale nie jest alternatywą dla new ArrayList<>(source). W Collections.copyrzeczywistości zakłada się, że destination.size()jest on co najmniej tak duży jak source.size(), a następnie kopiuje zakres indeks po indeksie za pomocą set(int,E)metody. Metoda nie dodaje nowych elementów do miejsca docelowego. Odwołaj się do kodu źródłowego, jeśli nie jest wystarczająco jasny z Javadoc.
Radiodef,
35

Tak l1i l2wskaże to samo odwołanie, ten sam obiekt.

Jeśli chcesz utworzyć nową ArrayList na podstawie innej ArrayList, wykonaj następujące czynności:

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

Wynik będzie l1nadal miał 2 elementy i l2będzie miał 3 elementy.

Alfredo Osorio
źródło
Czy możesz wyjaśnić różnicę między List<String> l2 = new ArrayList<String>(l1)i List<String> l2 = l1?
MortalMan
@MortalMan różnica polega na tym, że l2 = nowy ArrayList <String> (l1) jest całkowicie nowym obiektem, a modyfikacja l2 nie wpływa na l1, podczas gdy List <String> l2 = l1 nie tworzysz nowego obiektu, a jedynie odwołujesz się do niego obiekt jako l1, więc w tym przypadku wykonanie operacji takiej jak l2.add („Everybody”), l1.size () i l2.size () zwróci 3, ponieważ oba odnoszą się do tego samego obiektu.
Alfredo Osorio
19

Innym wygodnym sposobem kopiowania wartości z src ArrayList do dest Arraylist jest:

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

Jest to faktyczne kopiowanie wartości, a nie tylko kopiowanie referencji.

Harshal Waghmare
źródło
10
nie jestem do końca pewien, czy to jest dokładne. mój test pokazuje coś przeciwnego (wciąż odnoszącego się do tego samego obiektu)
invertigo
to rozwiązanie zadziałało dla mnie podczas korzystania z ArrayList z ArrayAdapter
albanx
1
Ta odpowiedź jest zła. addAll () po prostu kopiuje referencje, jak powiedział invertigo. To nie jest głęboka kopia.
jk7
W przypadku ArrayList <String> ta odpowiedź jest akceptowalna, ponieważ String jest niezmienny, ale spróbuj na przykładzie OP, ArraList <Integer>, a zobaczysz, że to tylko kopiowanie referencji.
jk7
Chyba nie tylko mój dzień. Okazuje się, że klasy takie jak Integer i Long są również niezmienne, więc odpowiedź Harshal działa w prostych przypadkach, takich jak ArrayList <Integer> i ArrayList <String>. To, co zawodzi, dotyczy złożonych obiektów, które nie są niezmienne.
jk7
8

Istnieje metoda addAll (), która posłuży do skopiowania jednej tablicy ArrayList do drugiej.

Na przykład masz dwie listy tablic : sourceList i targetList , użyj poniższego kodu.

targetList.addAll (sourceList);

vaibhav agrawal
źródło
kopiuje również referencje.
Vikash
4

Java nie przekazuje obiektów, przekazuje odniesienia (wskaźniki) do obiektów. Tak więc, l2 i l1 są dwoma wskaźnikami do tego samego obiektu.

Musisz utworzyć wyraźną kopię, jeśli potrzebujesz dwóch różnych list o tej samej zawartości.

JB Nizet
źródło
3
Jak zrobić „wyraźną kopię”? Przypuszczam, że mówisz o głębokiej kopii?
Cin316
1

List.copyOf ➙ lista niemodyfikowalna

Zapytałeś:

Czy nie ma innego sposobu przypisania kopii listy

Java 9 przyniosła List.ofmetody użycia literałów do stworzenia niemodyfikowalnej Listnieznanej konkretnej klasy.

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

Oprócz tego mamy również List.copyOf. Ta metoda również zwraca niemodyfikowalną Listnieznaną konkretną klasę.

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

Przez „niemodyfikowalny” rozumiemy liczbę elementów na liście, a odniesienie do obiektu utrzymywane w każdym gnieździe jako element jest stałe. Nie można dodawać, upuszczać ani zamieniać elementów. Ale odniesienie do obiektu utrzymywane w każdym elemencie może, ale nie musi, być zmienne .

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

Zobacz ten kod uruchamiany na żywo w IdeOne.com .

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

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

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

Zapytałeś o odwołania do obiektów. Jak powiedzieli inni, jeśli utworzysz jedną listę i przypiszesz ją do dwóch zmiennych odniesienia (wskaźników), nadal będziesz mieć tylko jedną listę. Oba wskazują na tę samą listę. Jeśli użyjesz dowolnego wskaźnika do zmodyfikowania listy, oba wskaźniki zobaczą później zmiany, ponieważ w pamięci jest tylko jedna lista.

Musisz więc zrobić kopię listy. Jeśli chcesz, aby ta kopia nie była modyfikowalna, użyj List.copyOfmetody opisanej w tej odpowiedzi. W tym podejściu powstają dwie osobne listy, każda z elementami zawierającymi odwołanie do tych samych obiektów treści. Na przykład w powyższym przykładzie, w którym Stringobiekty reprezentują kolory, obiekty kolorowe pływają gdzieś w pamięci. Dwie listy zawierają wskaźniki do obiektów tego samego koloru. Oto schemat.

wprowadź opis zdjęcia tutaj

Pierwsza lista colorsjest modyfikowalna. Oznacza to, że niektóre elementy można usunąć, jak pokazano w powyższym kodzie, w którym usunęliśmy oryginalny trzeci element Chartreuse(indeks 2 = porządek 3). I elementy mogą być dodawane. I elementy można zmienić, aby wskazywały na inne, Stringtakie jak OliveDrablubCornflowerBlue .

Natomiast cztery elementy masterColorssą ustalone. Bez usuwania, bez dodawania i bez zastępowania innego koloru. To Listwdrożenie jest niemodyfikowalne.

Basil Bourque
źródło