Come copiare un array in Java

1. Panoramica

In questo rapido articolo, discuteremo diversi metodi di copia degli array in Java. La copia di array può sembrare un'attività banale, ma può causare risultati imprevisti e comportamenti del programma se non eseguita con attenzione.

2. La classe di sistema

Cominciamo con la libreria Java di base - System.arrayCopy () ; questo copia un array da un array di origine a un array di destinazione, iniziando l'azione di copia dalla posizione di origine alla posizione di destinazione fino alla lunghezza specificata.

Il numero di elementi copiati nella matrice di destinazione è uguale alla lunghezza specificata. Fornisce un modo semplice per copiare una sotto-sequenza di un array in un altro.

Se uno degli argomenti della matrice è null, genera un'eccezione NullPointerException e se uno degli argomenti interi è negativo o fuori intervallo, genera un'eccezione IndexOutOfBoundException .

Diamo un'occhiata a un esempio per copiare un array completo su un altro usando la classe java.util.System :

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

Gli argomenti che questo metodo accetta sono; un array di origine, la posizione iniziale da copiare dall'array di origine, un array di destinazione, la posizione iniziale nell'array di destinazione e il numero di elementi da copiare.

Diamo un'occhiata a un altro esempio che mostra la copia di una sottosequenza da un array di origine a una destinazione:

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. La classe Arrays

La classe Arrays offre anche più metodi di overload per copiare un array in un altro. Internamente, utilizza lo stesso approccio fornito dalla classe System che abbiamo visto in precedenza. Fornisce principalmente due metodi, copyOf (…) e copyRangeOf (…) .

Diamo prima un'occhiata a copyOf :

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

È importante notare che la classe Arrays utilizza Math.min (…) per selezionare la lunghezza minima dell'array di origine e il valore del nuovo parametro di lunghezza per determinare la dimensione dell'array risultante.

Arrays.copyOfRange () accetta 2 parametri, " from" e " to" oltre al parametro array di origine. L'array risultante include l' indice " da" ma l'indice "a" è escluso. Vediamo un esempio:

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

Entrambi questi metodi eseguono una copia superficiale degli oggetti se applicati a un array di tipi di oggetti non primitivi. Vediamo un esempio di test case:

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

Poiché il risultato è una copia superficiale, una modifica nel nome del dipendente di un elemento dell'array originale ha causato il cambiamento nell'array di copia.

E così, se vogliamo fare una copia completa dei tipi non primitivi, possiamo scegliere le altre opzioni descritte nelle prossime sezioni.

4. Copia array con Object.clone ()

Object.clone () viene ereditato dalla classe Object in un array.

Copiamo prima un array di tipi primitivi usando il metodo clone:

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

E una prova che funziona:

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

L'esempio sopra mostra che hanno lo stesso contenuto dopo la clonazione ma contengono riferimenti diversi, quindi qualsiasi modifica in uno di essi non influirà sull'altro.

D'altra parte, se cloniamo un array di tipi non primitivi usando lo stesso metodo, i risultati saranno diversi.

Crea una copia superficiale degli elementi dell'array di tipo non primitivo, anche se la classe dell'oggetto racchiuso implementa l' interfaccia Cloneable e sovrascrive il metodo clone () dalla classe Object .

Diamo un'occhiata a un esempio:

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

Possiamo testare la nostra implementazione creando un nuovo array di indirizzi e invocando il nostro metodo clone () :

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

Questo esempio mostra che qualsiasi modifica nell'array originale o copiato provocherebbe il cambiamento nell'altro anche quando gli oggetti racchiusi sono clonabili .

5. Utilizzo dell'API Stream

Si scopre che possiamo usare l'API Stream anche per copiare gli array. Diamo un'occhiata a un esempio:

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

Per i tipi non primitivi, eseguirà anche una copia superficiale degli oggetti. Per saperne di più su Java 8 Streams , puoi iniziare qui.

6. Biblioteche esterne

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.

Il metodo da utilizzare dipende principalmente dallo scenario esatto. Finché stiamo usando un array di tipo primitivo, possiamo usare uno qualsiasi dei metodi offerti dalle classi System e Arrays . Non dovrebbe esserci alcuna differenza nelle prestazioni.

Per i tipi non primitivi, se è necessario eseguire una copia completa di un array, è possibile utilizzare SerializationUtils o aggiungere esplicitamente metodi clone alle nostre classi.

E come sempre, gli esempi mostrati in questo articolo sono disponibili su GitHub.