1. Översikt
I den här snabba artikeln kommer vi att diskutera olika matrisekopieringsmetoder i Java. Array-kopiering kan verka som en trivial uppgift, men det kan orsaka oväntade resultat och programbeteenden om de inte görs noggrant.
2. System Class
Låt oss börja med Java-biblioteket - System.arrayCopy () ; detta kopierar en matris från en källmatris till en destinationsmatris, och startar kopieringsåtgärden från källpositionen till målpositionen tills den angivna längden.
Antalet element som kopieras till målgruppen är lika med den angivna längden. Det ger ett enkelt sätt att kopiera en undersekvens av en matris till en annan.
Om något av arrayargumenten är null, kastar det en NullPointerException och om något av heltalargumenten är negativt eller utanför intervallet, kastar det en IndexOutOfBoundException .
Låt oss ta en titt på ett exempel för att kopiera en fullständig matris till en annan med klassen java.util.System :
int[] array = {23, 43, 55}; int[] copiedArray = new int[3]; System.arraycopy(array, 0, copiedArray, 0, 3);
Argument som denna metod tar är: en källmatris, startpositionen som ska kopieras från källmatrisen, en destinationsmatris, startpositionen i destinationsmatrisen och antalet element som ska kopieras.
Låt oss ta en titt på ett annat exempel som visar kopiering av en delsekvens från en källmatris till en destination:
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. Arrays- klassen
Den Arrays klassen erbjuder också flera överbelastade metoder för att kopiera en matris till en annan. Internt använder den samma metod som tillhandahålls av systemklassen som vi har sett tidigare. Det ger huvudsakligen två metoder, copyOf (…) och copyRangeOf (…) .
Låt oss ta en titt på copyOf först :
int[] array = {23, 43, 55, 12}; int newLength = array.length; int[] copiedArray = Arrays.copyOf(array, newLength);
Det är viktigt att notera att Arrays- klassen använder Math.min (...) för att välja minimum av källmatrislängden och värdet på den nya längdparametern för att bestämma storleken på den resulterande matrisen.
Arrays.copyOfRange () tar två parametrar, ' från' och ' till' förutom källmatrisparametern. Den resulterande matrisen inkluderar ' från' index men 'till' index är exkluderat. Låt oss se ett exempel:
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]);
Båda dessa metoder gör en grund kopia av objekt om de tillämpas på en uppsättning icke-primitiva objekttyper. Låt oss se ett exempel på testfall:
Employee[] copiedArray = Arrays.copyOf(employees, employees.length); employees[0].setName(employees[0].getName() + "_Changed"); assertArrayEquals(copiedArray, array);
Eftersom resultatet är en grund kopia - en ändring av anställds namn på ett element i den ursprungliga matrisen orsakade ändringen i kopieringsmatrisen.
Och så - om vi vill göra en djup kopia av icke-primitiva typer - kan vi gå till de andra alternativen som beskrivs i de kommande avsnitten.
4. Array Copy With Object.clone ()
Object.clone () ärvs från objektklassen i en matris.
Låt oss först kopiera en uppsättning primitiva typer med klonmetoden:
int[] array = {23, 43, 55, 12}; int[] copiedArray = array.clone();
Och ett bevis på att det fungerar:
assertArrayEquals(copiedArray, array); array[0] = 9; assertTrue(copiedArray[0] != array[0]);
Ovanstående exempel visar att de har samma innehåll efter kloning men de har olika referenser, så någon förändring i någon av dem påverkar inte den andra.
Å andra sidan, om vi klonar en uppsättning icke-primitiva typer med samma metod, blir resultaten olika.
Det skapar en grundkopia av de icke-primitiva typmatriselementen, även om det bifogade objektets klass implementerar det klonabla gränssnittet och åsidosätter metoden clone () från objektklassen .
Låt oss ta en titt på ett exempel:
public class Address implements Cloneable { // ... @Override protected Object clone() throws CloneNotSupportedException { super.clone(); Address address = new Address(); address.setCity(this.city); return address; } }
Vi kan testa vår implementering genom att skapa en ny rad adresser och åberopa vår klon () -metod:
Address[] addresses = createAddressArray(); Address[] copiedArray = addresses.clone(); addresses[0].setCity(addresses[0].getCity() + "_Changed");
assertArrayEquals(copiedArray, addresses);
Detta exempel visar att alla ändringar i den ursprungliga eller kopierade matrisen skulle orsaka förändringen i den andra även när de bifogade objekten är klonbara .
5. Använda Stream API
Det visar sig att vi också kan använda Stream API för att kopiera matriser. Låt oss ta en titt på ett exempel:
String[] strArray = {"orange", "red", "green'"}; String[] copiedArray = Arrays.stream(strArray).toArray(String[]::new);
För de icke-primitiva typerna kommer det också att göra en grunt kopia av objekt. Om du vill veta mer om Java 8 Streams kan du börja här.
6. Externa bibliotek
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.
Metoden att använda beror huvudsakligen på det exakta scenariot. Så länge vi använder en primitiv typmatris kan vi använda någon av metoderna som erbjuds av klasserna System och Arrays . Det borde inte vara någon skillnad i prestanda.
För icke-primitiva typer, om vi behöver göra en djup kopia av en matris kan vi antingen använda SerializationUtils eller lägga till klonmetoder till våra klasser uttryckligen.
Och som alltid är exemplen som visas i den här artikeln tillgängliga på GitHub.