Nie, to ważne pytanie. Java nie obsługuje „prawdziwych” typów ogólnych, z wymazywaniem typów w czasie wykonywania i wszystkimi innymi, więc tego rodzaju szczegóły mogą być trudne. Ponadto interfejs Cloneable i mechanizm metody Object.clone () są podobnie zagmatwane.
Outlaw Programmer
OK, głównie robię C #, gdzie jest to naprawdę łatwe. Daj mi znać, jeśli chcesz, abym usunął komentarze z tego pytania.
Espo
1
Możesz zostawić komentarz. Myślę, że moje zmiany wyjaśniły, z czym mam problem.
Bill the Lizard
2
Twój komentarz jest w porządku, choć trochę protekcjonalny. Wyobrażam sobie, że wiele przeszkód, przez które muszą przejść programiści Java, wydaje się głupim programistom .NET.
Outlaw Programmer
1
@Oscar, chce klonować, a nie wywoływać polecenia clone. Może to nie być to samo, co klon tak naprawdę nie klonuje. Myślę, że o to chodzi. To naprawdę trudne pytanie.
To zadziała dobrze w przypadku Strings (o co chodzi w pytaniu), ale warto zauważyć, że ArrayList.clone wykona płytką kopię, więc jeśli na liście znajdują się zmienne obiekty, nie zostaną one sklonowane (i zmieni jeden w jednej liście nie zmieni, że jedna na drugiej liście, jak również.
pkaeding
49
Należy unikać używania typów surowych w żadnym innym kodzie niż starszym. Lepiej użyj ArrayList<String> newArrayList = (ArrayList<String>) oldArrayList.clone();.
cdmckay
20
Szkoda, że ArrayList ma metodę #clone, ale sama List nie. Westchnienie.
rogerdpack
12
Nie powiązane, ale w tym momencie: użyj List<String>zamiast ArrayList<String>po lewej stronie. W ten sposób kolekcje powinny być używane przez większość czasu.
Christophe Roussy
3
Nie mogłem użyć tej metody do zduplikowania ArrayList. Nie rozpoznano metody clone ().
Jack
318
Dlaczego chcesz klonować? Tworzenie nowej listy ma zwykle większy sens.
Możesz nie wiedzieć, jaki to typ listy. Może to być LinkedList, MyOwnCustomList lub podklasa ArrayList, w którym to przypadku nowe ArrayList byłoby niepoprawnym typem.
Steve Kuo
51
Czy obchodzi mnie, której implementacji użyła oryginalna lista? Prawdopodobnie obchodzi mnie, której implementacji używa nowa lista.
Tom Hawtin - tackline
12
@Steve Kuo: Podpis ArrayList(Collection<? extends E> c)oznacza, że nie ma znaczenia, jakiego rodzaju listy użyjesz jako argumentu.
Można to zrobić tak jak List <AnObject> xy = new ArrayList <> (oldList);
mirzak
1
To nie jest głęboka kopia, zmiany w elementach jednej listy można zobaczyć w innej
Inchara
2
Gdzie w pytaniu określono, że wymagana jest głęboka kopia? Założenie jest takie, że wymagana jest inna kolekcja zawierająca te same obiekty. Jeśli chcesz zejść z głębokiej ścieżki kopiowania, otwierasz zupełnie nową puszkę robaków.
Simon Jenkins,
Nie jest to jednak klon, prawda? Z dokumentacji API „Nie ma gwarancji co do typu, zmienności, możliwości serializacji lub bezpieczeństwa wątków zwróconej listy”. Euw, nie chcę jednego z nich. toCollectionmoże być lepszym wyborem.
Tom Hawtin - tackline
16
Należy pamiętać, że Object.clone () ma poważne problemy i odradza się jego używanie w większości przypadków. Pełną odpowiedź można znaleźć w punkcie 11 książki „ Efektywna Java ” Joshuy Blocha. Uważam, że możesz bezpiecznie używać Object.clone () na tablicach typów prymitywnych, ale poza tym musisz rozsądnie używać i nadpisywać clone. Prawdopodobnie lepiej będzie zdefiniować konstruktor kopiujący lub statyczną metodę fabryki, która jawnie klonuje obiekt zgodnie z twoją semantyką.
Dlaczego po prostu nie użyć new ArrayList <String> (oldList)?
cdmckay
4
Wierzę, że to by nie zadziałało, z doc * Lista docelowa musi być przynajmniej tak długa, jak lista źródeł. Jeśli jest dłuższy, pozostałe elementy listy docelowej pozostają niezmienione.
Greg Domjan
@GregDomjan nie to, że zgadzam się, że to najlepszy sposób, ale jest to sposób na zrobienie tego. Aby obejść swój problem, jest to tak proste, jak to: List <String> newList = new ArrayList <> (oldList.size ());
nckbrz
1
Nie jestem pewien, czy jest to związane z Javą 8, ale nawet przy określaniu rozmiaru nadal pojawia się wyjątek IndexOutOfBoundsException: destination.size () <source.size (): 0 <2 on List<MySerializableObject> copyList = new ArrayList<>(mMySerializableObjects.size()); Wydaje się, że używanie copyList.addAll(original);jest dobrą alternatywą
Gene Bo
@GeneBo Nie określa rozmiaru. Określa pojemność, a to zupełnie inna sprawa. Radość z tajemniczych intargumentów. Nie mam pojęcia, dlaczego chcesz użyć tej mało znanej metody statycznej zamiast starej, dobrej addAll.
To zadziała w przypadku ciągów znaków, ale nie w przypadku obiektów modyfikowalnych. Te również będziesz chciał sklonować.
jodonnell
Tak, jego pytanie dotyczy strun. I ma problem z generykami, które tak naprawdę nie lubią rzeczy odlewniczych w tym przypadku.
Allain Lalonde,
Ponadto ArrayList.clone wykona tylko płytkie klonowanie, więc zmienne obiekty na liście również nie zostaną sklonowane przy użyciu tej metody.
rozpoczęcie
Powinno to być ArrayList <String> btw. Ponadto prawdopodobnie lepiej będzie, jeśli użyjesz nowej ArrayList <String> (oryginalna), ponieważ jest mniej pisana i równie przejrzysta.
cdmckay
4
Dlaczego po prostu nie użyć new ArrayList<String>(original)?
user102008
6
Jeśli chcesz tego, aby móc zwrócić Listę w getterze, lepiej byłoby zrobić:
Aby sklonować ogólny interfejs, taki jak java.util.Listty, wystarczy go przesłać. oto przykład:
List list =newArrayList();List list2 =((List)((ArrayList) list).clone());
Jest to trochę trudne, ale działa, jeśli jesteś ograniczony do zwrócenia pliku List interfejsu, więc każdy może zaimplementować twoją listę, kiedy tylko zechce.
Wiem, że ta odpowiedź jest bliska ostatecznej odpowiedzi, ale moja odpowiedź odpowiada, jak to wszystko zrobić, gdy pracujesz z List- generycznym rodzicem - nieArrayList
@JuanCarlosDiaz będzie, to jest zadawane pytanie było o ArrayList, więc odpowiedziałem to dla ArrayList :)
Ahmed hamdy
2
Zachowaj ostrożność podczas klonowania ArrayLists. Klonowanie w Javie jest płytkie. Oznacza to, że sklonuje tylko samego Arraylist, a nie jego członków. Więc jeśli masz ArrayList X1 i sklonujesz ją do X2, każda zmiana w X2 będzie również widoczna w X1 i odwrotnie. Podczas klonowania wygenerujesz tylko nową ArrayList ze wskaźnikami do tych samych elementów w oryginale.
Należy pamiętać, że jest to tylko płytka, a nie głęboka kopia, tj. otrzymasz nową listę, ale wpisy są takie same. Nie stanowi to problemu dla prostych strun. Get jest trudniejszy, gdy pozycje listy same w sobie są obiektami.
Nie ma żadnej gwarancji, że Listklasa implementacji ma publiczny konstruktor bez argumentów. Na przykład, Lists powroty przez Array.asList, List.oflub List.subListprawdopodobnie nie.
Odpowiedzi:
źródło
ArrayList<String> newArrayList = (ArrayList<String>) oldArrayList.clone();
.List<String>
zamiastArrayList<String>
po lewej stronie. W ten sposób kolekcje powinny być używane przez większość czasu.Dlaczego chcesz klonować? Tworzenie nowej listy ma zwykle większy sens.
Zadanie wykonane.
źródło
ArrayList(Collection<? extends E> c)
oznacza, że nie ma znaczenia, jakiego rodzaju listy użyjesz jako argumentu.Oto kod, którego używam do tego:
Nadzieja jest dla ciebie przydatna
źródło
ArrayList
używaćArrayList<YourObject>
ArrayList
konstruktora?W Javie 8 można go sklonować za pomocą strumienia.
...
źródło
toCollection
może być lepszym wyborem.Należy pamiętać, że Object.clone () ma poważne problemy i odradza się jego używanie w większości przypadków. Pełną odpowiedź można znaleźć w punkcie 11 książki „ Efektywna Java ” Joshuy Blocha. Uważam, że możesz bezpiecznie używać Object.clone () na tablicach typów prymitywnych, ale poza tym musisz rozsądnie używać i nadpisywać clone. Prawdopodobnie lepiej będzie zdefiniować konstruktor kopiujący lub statyczną metodę fabryki, która jawnie klonuje obiekt zgodnie z twoją semantyką.
źródło
Myślę, że to powinno załatwić sprawę przy użyciu Collection API:
Uwaga : metoda kopiowania działa w czasie liniowym.
źródło
List<MySerializableObject> copyList = new ArrayList<>(mMySerializableObjects.size());
Wydaje się, że używaniecopyList.addAll(original);
jest dobrą alternatywąint
argumentów. Nie mam pojęcia, dlaczego chcesz użyć tej mało znanej metody statycznej zamiast starej, dobrejaddAll
.Uważam, że użycie addAll działa dobrze.
zamiast generycznej składni używane są nawiasy
źródło
new ArrayList<String>(original)
?Jeśli chcesz tego, aby móc zwrócić Listę w getterze, lepiej byłoby zrobić:
źródło
Aby sklonować ogólny interfejs, taki jak
java.util.List
ty, wystarczy go przesłać. oto przykład:Jest to trochę trudne, ale działa, jeśli jesteś ograniczony do zwrócenia pliku
List
interfejsu, więc każdy może zaimplementować twoją listę, kiedy tylko zechce.Wiem, że ta odpowiedź jest bliska ostatecznej odpowiedzi, ale moja odpowiedź odpowiada, jak to wszystko zrobić, gdy pracujesz z
List
- generycznym rodzicem - nieArrayList
źródło
Zachowaj ostrożność podczas klonowania ArrayLists. Klonowanie w Javie jest płytkie. Oznacza to, że sklonuje tylko samego Arraylist, a nie jego członków. Więc jeśli masz ArrayList X1 i sklonujesz ją do X2, każda zmiana w X2 będzie również widoczna w X1 i odwrotnie. Podczas klonowania wygenerujesz tylko nową ArrayList ze wskaźnikami do tych samych elementów w oryginale.
źródło
Powinno to również działać:
źródło
Należy pamiętać, że jest to tylko płytka, a nie głęboka kopia, tj. otrzymasz nową listę, ale wpisy są takie same. Nie stanowi to problemu dla prostych strun. Get jest trudniejszy, gdy pozycje listy same w sobie są obiektami.
źródło
źródło
Nie jestem specjalistą od Java, ale mam ten sam problem i próbowałem rozwiązać tą metodą. (Zakłada się, że T ma konstruktora kopiującego).
źródło
List
klasa implementacji ma publiczny konstruktor bez argumentów. Na przykład,List
s powroty przezArray.asList
,List.of
lubList.subList
prawdopodobnie nie.