Ich habe eine ArrayList
und ich möchte sie genau kopieren. Ich verwende Utility-Klassen, wenn möglich, unter der Annahme, dass jemand einige Zeit damit verbracht hat, sie zu korrigieren. Am Ende habe ich natürlich die Collections
Klasse, die eine Kopiermethode enthält.
Angenommen, ich habe Folgendes:
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);
Dies schlägt fehl, weil es im Grunde b
nicht groß genug ist, um zu halten a
. Ja, ich weiß, b
hat Größe 0, aber es sollte jetzt groß genug sein, nicht wahr? Wenn ich b
zuerst füllen muss , Collections.copy()
wird es für mich zu einer völlig nutzlosen Funktion. Gibt es außer der Programmierung einer Kopierfunktion (die ich jetzt ausführen werde) einen geeigneten Weg, dies zu tun?
java
list
collections
copy
Jasper Floor
quelle
quelle
Antworten:
Berufung
erstellt eine flache Kopie von
a
innenb
. Alle Elemente existierenb
in genau derselben Reihenfolge, in der sie sich befandena
(vorausgesetzt, sie hatten eine Reihenfolge).Ebenso anrufen
erstellt auch eine flache Kopie von
a
innenb
. Wenn der erste Parameterb
nicht über genügend Kapazität (nicht Größe) verfügt, um allea
Elemente zu enthalten , wird ein ausgelöstIndexOutOfBoundsException
. Die Erwartung ist, dass keine Zuweisungen erforderlich sind, umCollections.copy
zu funktionieren, und wenn dies der Fall ist, wird diese Ausnahme ausgelöst. Es ist eine Optimierung, wenn die kopierte Sammlung vorab zugewiesen werden muss (b
), aber ich denke im Allgemeinen nicht, dass sich die Funktion aufgrund der erforderlichen Überprüfungen lohnt, da konstruktorbasierte Alternativen wie die oben gezeigte keine seltsamen Nebenwirkungen haben.Um eine tiefe Kopie zu erstellen
List
, müsste der über einen der beiden Mechanismen über komplizierte Kenntnisse des zugrunde liegenden Typs verfügen. BeiString
s, die in Java (und auch in .NET) unveränderlich sind, benötigen Sie nicht einmal eine tiefe Kopie. Im Fall vonMySpecialObject
müssen Sie wissen, wie Sie eine tiefe Kopie davon erstellen, und das ist keine generische Operation.Hinweis: Die ursprünglich akzeptierte Antwort war das Top-Ergebnis für
Collections.copy
Google und war, wie in den Kommentaren ausgeführt, völlig falsch.quelle
b
hat eine Kapazität von 3, aber eine Größe von 0. Die Tatsache, dassArrayList
eine Art Pufferkapazität vorhanden ist, ist ein Implementierungsdetail - es ist nicht Teil derList
Schnittstelle,Collections.copy(List, List)
verwendet es also nicht. Es wäre hässlich, wenn es sich um einen Sonderfall handeln würdeArrayList
.Wie MrWiggles angegeben hat, ist die Verwendung des ArrayList-Konstruktors, der eine Sammlung verwendet, der Weg in das bereitgestellte Beispiel.
Für kompliziertere Szenarien (die möglicherweise Ihren echten Code enthalten) sind die Sammlungen in Guava möglicherweise hilfreich.
quelle
Mach einfach:
ArrayList verfügt über einen Konstruktor, der eine andere Sammlung zum Kopieren der Elemente akzeptiert
quelle
String
Objekte unveränderlich sind.Die Antwort von Stephen Katulka (akzeptierte Antwort) ist falsch (zweiter Teil). Es erklärt, dass
Collections.copy(b, a);
eine tiefe Kopie, die es nicht tut. Beidesnew ArrayList(a);
undCollections.copy(b, a);
nur eine flache Kopie. Der Unterschied besteht darin, dass der Konstruktor neuen Speicher zuweist undcopy(...)
nicht, was ihn in Fällen geeignet macht, in denen Sie Arrays wiederverwenden können, da er dort einen Leistungsvorteil hat.Die Java-Standard-API versucht, die Verwendung von Deep Copies zu verhindern, da es schlecht wäre, wenn neue Codierer dies regelmäßig verwenden würden. Dies kann auch einer der Gründe sein, warum dies
clone()
nicht standardmäßig öffentlich ist.Der Quellcode für
Collections.copy(...)
kann in Zeile 552 unter folgender Adresse eingesehen werden: http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Core/Collections-Jar-Zip-Logging-regex/java/util/ Collections.java.htmWenn Sie eine tiefe Kopie benötigen, müssen Sie die Elemente manuell durchlaufen, indem Sie für jedes Objekt eine for-Schleife und einen Klon () verwenden.
quelle
Der einfachste Weg, eine Liste zu kopieren, besteht darin, sie an den Konstruktor der neuen Liste zu übergeben:
b
wird eine flache Kopie von seina
Wenn man sich die Quelle von
Collections.copy(List,List)
(ich hatte es noch nie gesehen) ansieht, scheint es für das Kopieren der Elemente Index für Index zu sein. Wenn SieList.set(int,E)
also Element 0 verwenden, wird Element 0 in die Zielliste usw. usw. überschrieben. Nicht besonders klar aus den Javadocs, die ich zugeben müsste.quelle
legt die Größe nicht fest. Hiermit wird die anfängliche Kapazität festgelegt (dh wie viele Elemente es aufnehmen kann, bevor die Größe geändert werden muss). Eine einfachere Möglichkeit zum Kopieren ist in diesem Fall:
quelle
Wie Hoijui erwähnt. Die ausgewählte Antwort von Stephen Katulka enthält einen falschen Kommentar zu Collections.copy. Der Autor hat es wahrscheinlich akzeptiert, weil die erste Codezeile die Kopie machte, die er wollte. Der zusätzliche Aufruf von Collections.copy wird nur erneut kopiert. (Dies führt dazu, dass die Kopie zweimal erfolgt).
Hier ist Code, um es zu beweisen.
quelle
Die meisten Antworten hier erkennen das Problem nicht, der Benutzer möchte eine KOPIE der Elemente von der ersten Liste zur zweiten Liste haben, Ziellistenelemente sind neue Objekte und verweisen nicht auf die Elemente der ursprünglichen Liste. (bedeutet, dass das Ändern eines Elements der zweiten Liste die Werte für das entsprechende Element der Quellliste nicht ändern sollte.) Für die veränderlichen Objekte können wir den Konstruktor ArrayList (Collection) nicht verwenden, da er sich einfach auf das ursprüngliche Listenelement bezieht und nicht kopiert. Beim Kopieren benötigen Sie für jedes Objekt einen Listenkloner.
quelle
Warum verwenden Sie nicht einfach die
addAll
Methode:selbst wenn Sie bereits Elemente in b haben oder einige Elemente danach anhängen möchten, z.
quelle
Wenn Sie eine ArrayList kopieren möchten, kopieren Sie sie mit:
quelle
Strings können tief kopiert werden
weil sie unveränderlich sind. Jedes andere Objekt nicht -> Sie müssen iterieren und selbst eine Kopie erstellen.
quelle
b
auf dasselbe entsprechendeString
Objekt in zeigta
. Dies ist jedoch nicht wichtig, daString
Objekte , wie Sie hervorheben, unveränderlich sind.quelle
Jedes andere Objekt nicht -> Sie müssen iterieren und selbst eine Kopie erstellen.
Um dies zu vermeiden, implementieren Sie Cloneable.
....
quelle
Die folgende Ausgabe zeigt die Ergebnisse der Verwendung des Kopierkonstruktors und von Collections.copy ():
Die Quelle des vollständigen Programms finden Sie hier: Java-Listenkopie . Die Ausgabe reicht jedoch aus, um zu sehen, wie sich java.util.Collections.copy () verhält.
quelle
Und wenn Sie Google Guava verwenden, wäre die einzeilige Lösung
Dadurch wird eine veränderbare Array-Listeninstanz erstellt.
quelle
Da Java 8 nullsicher ist, können Sie den folgenden Code verwenden.
Oder mit einem Sammler
quelle
Kopieren ist nicht nutzlos, wenn Sie sich den Anwendungsfall vorstellen, einige Werte in eine vorhandene Sammlung zu kopieren. Dh Sie möchten vorhandene Elemente überschreiben, anstatt sie einzufügen.
Ein Beispiel: 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]
Ich würde jedoch eine Kopiermethode erwarten, die zusätzliche Parameter für den Startindex der Quell- und Zielsammlung sowie einen Parameter für die Anzahl benötigt.
Siehe Java BUG 6350752
quelle
Um zu verstehen, warum Collections.copy () eine IndexOutOfBoundsException auslöst, obwohl Sie das Hintergrundarray der Zielliste groß genug gemacht haben (über den Aufruf size () in der Quellliste), lesen Sie die Antwort von Abhay Yadav in dieser verwandten Frage: Gewusst wie Kopieren Sie eine java.util.List in eine andere java.util.List
quelle