So kopieren Sie ein Array in Java

So kopieren Sie ein Array in Java

1. Overview

In diesem kurzen Artikel werden verschiedene Methoden zum Kopieren von Arrays in Java erläutert. Das Kopieren von Arrays scheint eine triviale Aufgabe zu sein, kann jedoch zu unerwarteten Ergebnissen und Programmverhalten führen, wenn es nicht sorgfältig ausgeführt wird.

2. DieSystem Klasse

Beginnen wir mit der Java-Kernbibliothek -System.arrayCopy(); Dadurch wird ein Array von einem Quellarray in ein Zielarray kopiert und die Kopieraktion von der Quellposition zur Zielposition bis zur angegebenen Länge gestartet.

Die Anzahl der in das Zielarray kopierten Elemente entspricht der angegebenen Länge. Es bietet eine einfache Möglichkeit, eine Teilsequenz eines Arrays in eine andere zu kopieren.

Wenn eines der Array-Argumentenull, ist, wird einNullPointerException ausgelöst, und wenn eines der ganzzahligen Argumente negativ ist oder außerhalb des Bereichs liegt, wird einIndexOutOfBoundException ausgelöst.

Schauen wir uns ein Beispiel an, um ein vollständiges Array mit der Klassejava.util.Systemin ein anderes zu kopieren:

int[] array = {23, 43, 55};
int[] copiedArray = new int[3];

System.arraycopy(array, 0, copiedArray, 0, 3);

Argumente für diese Methode sind: ein Quell-Array, die zu kopierende Startposition aus dem Quell-Array, ein Ziel-Array, die Startposition im Ziel-Array und die Anzahl der zu kopierenden Elemente.

Schauen wir uns ein anderes Beispiel an, das das Kopieren einer Teilsequenz von einem Quellarray in ein Ziel zeigt:

int[] array = {23, 43, 55, 12, 65, 88, 92};
int[] copiedArray = new int[3];

System.arraycopy(array, 2, copiedArray, 0, 3);
assertTrue(3 == copiedArray.length);
assertTrue(copiedArray[0] == array[2]);
assertTrue(copiedArray[1] == array[3]);
assertTrue(copiedArray[2] == array[4]);

3. DieArrays Klasse

Die KlasseArraysbietet auch mehrere überladene Methoden zum Kopieren eines Arrays in ein anderes. Intern wird der gleiche Ansatz der KlasseSystemverwendet, den wir zuvor gesehen haben. Es werden hauptsächlich zwei Methoden bereitgestellt:copyOf(…) undcopyRangeOf(…).

Schauen wir unscopyOf erste: an

int[] array = {23, 43, 55, 12};
int newLength = array.length;

int[] copiedArray = Arrays.copyOf(array, newLength);

Es ist wichtig zu beachten, dass die KlasseArraysMath.min(…) verwendet, um das Minimum der Länge des Quellarrays und den Wert des neuen Längenparameters auszuwählen, um die Größe des resultierenden Arrays zu bestimmen.

Arrays.copyOfRange() verwendet zusätzlich zum Parameter des Quellarrays zwei Parameter,from' undto'. Das resultierende Array enthält den Indexfrom', der Index‘to'ist jedoch ausgeschlossen. Sehen wir uns ein Beispiel an:

int[] array = {23, 43, 55, 12, 65, 88, 92};

int[] copiedArray = Arrays.copyOfRange(array, 1, 4);
assertTrue(3 == copiedArray.length);
assertTrue(copiedArray[0] == array[1]);
assertTrue(copiedArray[1] == array[2]);
assertTrue(copiedArray[2] == array[3]);

Beide Methodendo a shallow copy von Objekten, wenn sie auf ein Array nicht primitiver Objekttypen angewendet werden. Sehen wir uns einen beispielhaften Testfall an:

Employee[] copiedArray = Arrays.copyOf(employees, employees.length);

employees[0].setName(employees[0].getName() + "_Changed");

assertArrayEquals(copiedArray, array);

Weil das Ergebnis eine flache Kopie ist - eine Änderung des Mitarbeiternamens eines Elements des ursprünglichen Arrays verursachte die Änderung des Kopienarrays.

Wenn wir also eine gründliche Kopie nicht-primitiver Typen erstellen möchten, können wir die anderen Optionen wählen, die in den nächsten Abschnitten beschrieben werden.

4. Array-Kopie mitObject.clone()

Object.clone() wird von der KlasseObjectin einem Array geerbt.

Kopieren wir zunächst ein Array primitiver Typen mithilfe der Klonmethode:

int[] array = {23, 43, 55, 12};

int[] copiedArray = array.clone();

Und ein Beweis, dass es funktioniert:

assertArrayEquals(copiedArray, array);
array[0] = 9;

assertTrue(copiedArray[0] != array[0]);

Das obige Beispiel zeigt, dass nach dem Klonen derselbe Inhalt vorhanden ist, die jedoch unterschiedliche Verweise enthalten, sodass sich Änderungen an einem dieser Verweise nicht auf den anderen auswirken.

Wenn wir dagegen ein Array nicht-primitiver Typen mit derselben Methode klonen, sind die Ergebnisse unterschiedlich.

Es werdena shallow copy der Array-Elemente vom nicht-primitiven Typ erstellt, selbst wenn die Klasse des eingeschlossenen Objekts die SchnittstelleCloneableimplementiert und die Methodeclone() aus der KlasseObjectüberschreibt.

Schauen wir uns ein Beispiel an:

public class Address implements Cloneable {
    // ...

    @Override
    protected Object clone() throws CloneNotSupportedException {
         super.clone();
         Address address = new Address();
         address.setCity(this.city);

         return address;
    }
}

Wir können unsere Implementierung testen, indem wir ein neues Adressarray erstellen und die Methodeclone()aufrufen:

Address[] addresses = createAddressArray();
Address[] copiedArray = addresses.clone();
addresses[0].setCity(addresses[0].getCity() + "_Changed");
assertArrayEquals(copiedArray, addresses);

Dieses Beispiel zeigt, dass jede Änderung des ursprünglichen oder kopierten Arrays die Änderung des anderen Arrays verursachen würde, selbst wenn die eingeschlossenen ObjekteCloneable sind.

5. Verwenden derStream-API

Es stellt sich heraus, dass wir die Stream-API auch zum Kopieren von Arrays verwenden können. Schauen wir uns ein Beispiel an:

String[] strArray = {"orange", "red", "green'"};
String[] copiedArray = Arrays.stream(strArray).toArray(String[]::new);

Für die nicht-primitiven Typen wird auch eine flache Kopie von Objekten erstellt. Um mehr überJava 8 Streams zu erfahren, können Siehere starten.

6. Externe Bibliotheken

Apache Commons 3 bietet eine Dienstprogrammklasse namensSerializationUtils, die eineclone(…)-Methode bereitstellt. Es ist sehr nützlich, wenn wir eine tiefe Kopie eines Arrays nicht-primitiver Typen erstellen müssen. Es kann vonhere heruntergeladen werden und seine Maven-Abhängigkeit ist:


    org.apache.commons
    commons-lang3
    3.5

Schauen wir uns einen Testfall an:

public class Employee implements Serializable {
    // fields
    // standard getters and setters
}

Employee[] employees = createEmployeesArray();
Employee[] copiedArray = SerializationUtils.clone(employees);
employees[0].setName(employees[0].getName() + "_Changed");
assertFalse(
  copiedArray[0].getName().equals(employees[0].getName()));

Diese Klasse erfordert, dass jedes Objekt dieSerializable-Schnittstelle implementiert. In Bezug auf die Leistung ist das Kopieren der Objekte in unserem Objektdiagramm langsamer als die manuell geschriebenen Klonmethoden.

7. Fazit

In diesem Tutorial haben wir uns die verschiedenen Optionen zum Kopieren eines Arrays in Java angesehen.

Die zu verwendende Methode hängt hauptsächlich vom genauen Szenario ab. Solange wir ein primitives Array verwenden, können wir jede der Methoden verwenden, die von den KlassenSystem undArrays angeboten werden. Es sollte keinen Leistungsunterschied geben.

Wenn wir für nicht-primitive Typen eine tiefe Kopie eines Arrays erstellen müssen, können wir entweder dieSerializationUtils verwenden oder unseren Klassen explizit Klonmethoden hinzufügen.

Und wie immer sind die in diesem Artikel gezeigten Beispiele fürover on GitHub verfügbar.