So kopieren Sie ein Array in Java

1. Übersicht

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

2. Die System - 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-Argumente null ist, wird eine NullPointerException ausgelöst, und wenn eines der ganzzahligen Argumente negativ ist oder außerhalb des Bereichs liegt, wird eine IndexOutOfBoundException ausgelöst .

Schauen wir uns ein Beispiel an, um ein vollständiges Array mit der Klasse java.util.System in ein anderes zu kopieren :

int[] array = {23, 43, 55}; int[] copiedArray = new int[3]; System.arraycopy(array, 0, copiedArray, 0, 3);

Argumente, die diese Methode annimmt, sind: ein Quellarray, die Startposition zum Kopieren aus dem Quellarray, ein Zielarray, die Startposition im Zielarray 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. Die Arrays- Klasse

Die Arrays- Klasse bietet auch mehrere überladene Methoden zum Kopieren eines Arrays in ein anderes. Intern wird derselbe Ansatz der Systemklasse verwendet , den wir zuvor gesehen haben. Es werden hauptsächlich zwei Methoden bereitgestellt : copyOf (…) und copyRangeOf (…) .

Schauen wir uns zuerst copyOf an :

int[] array = {23, 43, 55, 12}; int newLength = array.length; int[] copiedArray = Arrays.copyOf(array, newLength); 

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

Arrays.copyOfRange () verwendet zusätzlich zum Quellarray- Parameter zwei Parameter, ' von' und ' bis' . Das resultierende Array enthält den ' from'- Index, der ' to'- Index 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 Methoden erstellen eine flache Kopie 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);

Da das Ergebnis eine flache Kopie ist, hat eine Änderung des Mitarbeiternamens eines Elements des ursprünglichen Arrays die Änderung des Kopierarrays verursacht.

Wenn wir also eine tiefe Kopie nicht-primitiver Typen erstellen möchten, können wir uns für die anderen Optionen entscheiden, die in den nächsten Abschnitten beschrieben werden.

4. Array-Kopie mit Object.clone ()

Object.clone () wird von der Object- Klasse in einem Array geerbt .

Kopieren wir zunächst ein Array primitiver Typen mit 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, sie jedoch unterschiedliche Verweise enthalten, sodass sich Änderungen an den anderen nicht auf den anderen auswirken.

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

Es wird eine flache Kopie der Array-Elemente vom nicht-primitiven Typ erstellt, selbst wenn die Klasse des eingeschlossenen Objekts die klonbare Schnittstelle implementiert und die clone () -Methode aus der Object- Klasse ü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 unsere clone () -Methode 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 Objekte klonbar sind .

5. Verwenden der Stream- 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 über Java 8 Streams zu erfahren , können Sie hier beginnen.

6. Externe Bibliotheken

Apache Commons 3 offers a utility class called SerializationUtils that provides a clone(…) method. It is very useful if we need to do a deep copy of an array of non-primitive types. It can be downloaded from here and its Maven dependency is:

 org.apache.commons commons-lang3 3.5  

Let's have a look at a test case:

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

This class requires that each object should implement the Serializable interface. In terms of performance, it is slower than the clone methods written manually for each of the objects in our object graph to copy.

7. Conclusion

In this tutorial, we had a look at the various options to copy an array in Java.

Die zu verwendende Methode hängt hauptsächlich vom genauen Szenario ab. Solange wir ein primitives Array verwenden, können wir alle Methoden verwenden, die von den Klassen System und Arrays 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 die SerializationUtils verwenden oder unseren Klassen explizit Klonmethoden hinzufügen.

Und wie immer sind die in diesem Artikel gezeigten Beispiele auf GitHub verfügbar.