Mam ArrayList
i chcę go dokładnie skopiować. Gdy to możliwe, używam klas użytkowych, zakładając, że ktoś poświęcił trochę czasu na poprawienie tego. Więc naturalnie otrzymuję Collections
klasę, która zawiera metodę kopiowania.
Załóżmy, że mam:
List<String> a = new ArrayList<String>();
a.add("a");
a.add("b");
a.add("c");
List<String> b = new ArrayList<String>(a.size());
Collections.copy(b,a);
To się nie udaje, ponieważ zasadniczo uważa, że b
nie jest wystarczająco duży, aby go pomieścić a
. Tak, wiem, że b
ma rozmiar 0, ale teraz powinien być wystarczająco duży, prawda? Jeśli muszę b
najpierw wypełnić , to Collections.copy()
w moim umyśle staje się całkowicie bezużyteczną funkcją. Więc poza programowaniem funkcji kopiowania (co teraz zrobię), czy istnieje właściwy sposób na zrobienie tego?
java
list
collections
copy
Jasper Floor
źródło
źródło
Odpowiedzi:
Powołanie
tworzy płytką kopię
a
wewnątrzb
. Wszystkie elementy będą istniałyb
w dokładnie tej samej kolejności, w jakiej się znajdowałya
(zakładając, że ma kolejność).Podobnie dzwoniąc
tworzy również płytką kopię
a
wewnątrzb
. Jeśli pierwszy parametrb
,, nie ma wystarczającej pojemności (nie rozmiaru), aby pomieścić wszystkiea
elementy, to wyrzuciIndexOutOfBoundsException
. Oczekuje się, że żadne alokacje nie będą wymaganeCollections.copy
do działania, a jeśli takowe są, zgłasza ten wyjątek. Jest to optymalizacja wymagająca, aby skopiowana kolekcja była wstępnie przydzielona (b
), ale generalnie nie uważam, że ta funkcja jest tego warta ze względu na wymagane kontrole, biorąc pod uwagę alternatywy oparte na konstruktorach, takie jak ta pokazana powyżej, które nie mają dziwnych skutków ubocznych.Aby utworzyć głęboką kopię, za
List
pośrednictwem dowolnego mechanizmu musiałby mieć skomplikowaną wiedzę o typie bazowym. W przypadkuString
s, które są niezmienne w Javie (i .NET w tym przypadku), nie potrzebujesz nawet głębokiej kopii. W przypadkuMySpecialObject
, musisz wiedzieć, jak zrobić jego głęboką kopię i nie jest to operacja ogólna.Uwaga: pierwotnie zaakceptowana odpowiedź była najwyższym wynikiem
Collections.copy
w Google i była całkowicie błędna, jak wskazano w komentarzach.źródło
b
ma pojemność 3, ale rozmiar 0. Fakt, żeArrayList
ma jakąś pojemność bufora, jest szczegółem implementacji - nie jest częściąList
interfejsu, więcCollections.copy(List, List)
go nie używa. Byłoby to brzydkie w wyjątkowych przypadkachArrayList
.Jak wskazał MrWiggles, w podanym przykładzie sposobem jest użycie konstruktora ArrayList, który pobiera kolekcję.
W przypadku bardziej skomplikowanych scenariuszy (które mogą obejmować Twój prawdziwy kod), kolekcje w Guava mogą okazać się przydatne.
źródło
Po prostu zrób:
ArrayList ma konstruktora, który zaakceptuje inną Collection do skopiowania elementów
źródło
String
obiekty są niezmienne.Odpowiedź Stephena Katulki (odpowiedź przyjęta) jest błędna (część druga). Wyjaśnia, że
Collections.copy(b, a);
robi głęboką kopię, której nie robi. Jednonew ArrayList(a);
iCollections.copy(b, a);
drugie, zrób tylko płytką kopię. Różnica polega na tym, że konstruktor przydziela nową pamięć, acopy(...)
nie, co czyni go odpowiednim w przypadkach, w których można ponownie używać tablic, ponieważ ma tam przewagę wydajności.Standardowy interfejs API języka Java próbuje zniechęcać do korzystania z głębokich kopii, ponieważ byłoby źle, gdyby nowi programiści używali go regularnie, co może być również jednym z powodów, dla
clone()
których domyślnie nie jest on publiczny.Kod źródłowy
Collections.copy(...)
można znaleźć w linii 552 pod adresem : http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Core/Collections-Jar-Zip-Logging-regex/java/util/ Collections.java.htmJeśli potrzebujesz głębokiej kopii, musisz ręcznie iterować po elementach, używając pętli for i clone () na każdym obiekcie.
źródło
najprostszym sposobem skopiowania listy jest przekazanie jej do konstruktora nowej listy:
b
będzie płytką kopiąa
Patrząc na źródło
Collections.copy(List,List)
(nigdy wcześniej tego nie widziałem) wydaje się, że chodzi o radzenie sobie z indeksem elementów po indeksie. użycieList.set(int,E)
elementu 0 spowoduje nadpisanie elementu 0 na liście docelowej itp. Nie jest to szczególnie jasne z javadocs, które muszę przyznać.źródło
nie ustawia rozmiaru. Ustawia początkową pojemność (czyli ile elementów może pomieścić, zanim będzie trzeba zmienić rozmiar). Prostszym sposobem kopiowania w tym przypadku jest:
źródło
Jak wspomina Hoijui. Wybrana odpowiedź od Stephena Katulki zawiera niepoprawny komentarz dotyczący Collections.copy. Autor prawdopodobnie to zaakceptował, ponieważ pierwsza linia kodu wykonywała kopię, której chciał. Dodatkowe wywołanie Collections.copy po prostu kopiuje ponownie. (Powoduje to dwukrotne wykonanie kopii).
Oto kod, który to udowodni.
źródło
Większość odpowiedzi tutaj nie zdaje sobie sprawy z problemu, użytkownik chce mieć KOPIĘ elementów z pierwszej listy do drugiej listy, elementy listy docelowej to nowe obiekty, a nie odniesienia do elementów oryginalnej listy. (oznacza, że zmiana elementu drugiej listy nie powinna zmieniać wartości dla odpowiedniego elementu listy źródłowej.) W przypadku obiektów mutowalnych nie możemy użyć konstruktora ArrayList (Collection), ponieważ będzie on po prostu odnosił się do oryginalnego elementu listy i nie będzie kopiowany. Podczas kopiowania musisz mieć klonera listy dla każdego obiektu.
źródło
Dlaczego po prostu nie używasz
addAll
metody:nawet jeśli masz istniejące elementy w b lub chcesz zawiesić po nim niektóre elementy, takie jak:
źródło
Jeśli chcesz skopiować ArrayList, skopiuj ją za pomocą:
źródło
Ciągi można kopiować głęboko
ponieważ są niezmienne. Każdy inny obiekt nie -> musisz samemu powtórzyć i zrobić kopię.
źródło
b
wskazuje na ten sam odpowiedniString
obiekt wa
. Nie jest to jednak ważne, ponieważ, jak zauważyłeś,String
obiekty są niezmienne.źródło
Każdy inny obiekt nie -> musisz samemu powtórzyć i zrobić kopię.
Aby uniknąć tego narzędzia Cloneable.
....
źródło
Poniższe dane wyjściowe ilustrują wyniki użycia konstruktora kopiującego i Collections.copy ():
Źródło pełnego programu jest tutaj: kopia listy Java . Ale dane wyjściowe są wystarczające, aby zobaczyć, jak zachowuje się java.util.Collections.copy ().
źródło
A jeśli używasz google guava, rozwiązaniem będzie jedna linia
Tworzy to zmienną instancję listy tablic.
źródło
Ponieważ Java 8 jest bezpieczna dla wartości null, możesz użyć następującego kodu.
Lub za pomocą kolektora
źródło
Kopiowanie nie jest bezużyteczne, jeśli wyobrażasz sobie przypadek użycia kopiowania niektórych wartości do istniejącej kolekcji. To znaczy chcesz nadpisać istniejące elementy zamiast wstawiać.
Przykład: a = [1,2,3,4,5] b = [2,2,2,2,3,3,3,3,3,4,4,4,] a.copy (b) = [1,2,3,4,5,3,3,3,3,4,4,4]
Spodziewałbym się jednak metody kopiowania, która wymagałaby dodatkowych parametrów dla indeksu początkowego kolekcji źródłowej i docelowej, a także parametru dla count.
Zobacz Java BUG 6350752
źródło
Aby zrozumieć, dlaczego Collections.copy () zgłasza wyjątek IndexOutOfBoundsException, mimo że tablica zapasowa listy docelowej jest wystarczająco duża (za pomocą wywołania size () w sourceList), zobacz odpowiedź Abhaya Yadava w tym pokrewnym pytaniu: Jak skopiuj java.util.List do innej java.util.List
źródło