Cum să copiați o matrice în Java

1. Prezentare generală

În acest articol rapid, vom discuta despre diferite metode de copiere matrice în Java. Copierea matricei poate părea o sarcină banală, dar poate provoca rezultate neașteptate și comportamente ale programului dacă nu este realizată cu atenție.

2. Clasa de sistem

Să începem cu biblioteca Java de bază - System.arrayCopy () ; aceasta copiază o matrice dintr-o matrice sursă într-o matrice de destinație, începând acțiunea de copiere din poziția sursă în poziția țintă până la lungimea specificată.

Numărul de elemente copiate în matricea țintă este egal cu lungimea specificată. Oferă o modalitate ușoară de a copia o sub-secvență a unei matrice la alta.

Dacă oricare dintre argumentele matrice este nul, aruncă o NullPointerException și dacă oricare dintre argumentele întregi este negativ sau în afara intervalului, aruncă o IndexOutOfBoundException .

Să aruncăm o privire la un exemplu pentru a copia o matrice completă la alta folosind clasa java.util.System :

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

Argumentele pe care le ia această metodă sunt; o matrice sursă, poziția inițială de copiat din matricea sursă, o matrice destinație, poziția inițială în matricea destinație și numărul de elemente care trebuie copiate.

Să aruncăm o privire la un alt exemplu care arată copierea unei secvențe secundare dintr-o matrice sursă într-o destinație:

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. Clasa Matrici

Matricele clasă oferă , de asemenea , mai multe metode supraîncărcate pentru a copia o matrice la alta. Pe plan intern, folosește aceeași abordare oferită de clasa System pe care am văzut-o mai devreme. Acesta oferă în principal două metode, copyOf (...) și copyRangeOf (...) .

vedem mai întâi copyOf :

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

Este important să rețineți că clasa Arrays folosește Math.min (...) pentru selectarea minimului lungimii matricei sursă și a valorii noului parametru lungime pentru a determina dimensiunea matricei rezultate.

Arrays.copyOfRange () ia 2 parametri, „de la” și „ la” în plus față de parametrul sursei matrice. Matricea rezultată include indexul „de la”, dar indexul „la” este exclus. Să vedem un exemplu:

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

Ambele metode fac o copie superficială a obiectelor dacă sunt aplicate pe o matrice de tipuri de obiecte neprimitive. Să vedem un exemplu de caz de testare:

Employee[] copiedArray = Arrays.copyOf(employees, employees.length); employees[0].setName(employees[0].getName() + "_Changed"); assertArrayEquals(copiedArray, array);

Deoarece rezultatul este o copie superficială - o modificare a numelui angajatului unui element din matricea originală a provocat modificarea matricei de copiere.

Și așa - dacă vrem să facem o copie profundă a tipurilor neprimitive - putem alege celelalte opțiuni descrise în secțiunile viitoare.

4. Array Copy With Object.clone ()

Object.clone () este moștenit de la clasa Object într-o matrice.

Să copiem mai întâi o serie de tipuri primitive folosind metoda clonării:

int[] array = {23, 43, 55, 12}; int[] copiedArray = array.clone(); 

Și o dovadă că funcționează:

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

Exemplul de mai sus arată că au același conținut după clonare, dar conțin referințe diferite, astfel încât orice modificare a uneia dintre ele nu o va afecta pe cealaltă.

Pe de altă parte, dacă clonăm o serie de tipuri neprimitive folosind aceeași metodă, atunci rezultatele vor fi diferite.

Se creează o copie superficială a elementelor matrice de tip neprimitiv, chiar dacă clasa obiectului închis implementează interfața Cloneable și suprascrie metoda clone () din clasa Object .

Să aruncăm o privire la un exemplu:

public class Address implements Cloneable { // ... @Override protected Object clone() throws CloneNotSupportedException { super.clone(); Address address = new Address(); address.setCity(this.city); return address; } } 

Ne putem testa implementarea creând o nouă matrice de adrese și invocând metoda noastră clone () :

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

Acest exemplu arată că orice modificare în matricea originală sau copiată ar provoca schimbarea în cealaltă, chiar și atunci când obiectele închise sunt Clonabile .

5. Utilizarea API-ului Stream

Se pare că putem folosi și API-ul Stream pentru copierea matricelor. Să aruncăm o privire la un exemplu:

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

Pentru tipurile neprimitive, va face, de asemenea, o copie superficială a obiectelor. Pentru a afla mai multe despre fluxurile Java 8 , puteți începe aici.

6. Biblioteci externe

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.

Metoda de utilizat depinde în principal de scenariul exact. Atâta timp cât folosim o matrice de tip primitiv, putem folosi oricare dintre metodele oferite de clasele System și Arrays . Nu ar trebui să existe nicio diferență de performanță.

Pentru tipurile neprimitive, dacă trebuie să facem o copie profundă a unui tablou, putem folosi fie SerializationUtils, fie adăugăm în mod explicit metode de clonare la clasele noastre.

Și ca întotdeauna, exemplele prezentate în acest articol sunt disponibile pe GitHub.