Hvordan kopiere en matrise i Java

1. Oversikt

I denne raske artikkelen vil vi diskutere forskjellige matrikekopieringsmetoder i Java. Matrixkopi kan virke som en triviell oppgave, men det kan føre til uventede resultater og programatferd hvis den ikke gjøres nøye.

2. Den System Klasse

La oss starte med kjernen i Java-biblioteket - System.arrayCopy (); dette kopierer en matrise fra en kildematrise til en destinasjonsmatrise, og starter kopieringshandlingen fra kildeposisjonen til målposisjonen til den angitte lengden.

Antall elementer som er kopiert til målgruppen er lik den angitte lengden. Det gir en enkel måte å kopiere en undersekvens av en matrise til en annen.

Hvis noen av arrayargumentene er null, det kaster en NullPointerException og hvis noen av heltallargumentene er negative eller utenfor rekkevidden, kaster det et IndexOutOfBoundException.

La oss se på et eksempel for å kopiere et komplett utvalg til et annet ved hjelp av java.util.System klasse:

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

Argumenter denne metoden tar er; en kildematrise, startposisjonen for å kopiere fra kildearrayen, en destinasjonsmatrise, startposisjonen i destinasjonsmatrisen og antall elementer som skal kopieres.

La oss ta en titt på et annet eksempel som viser kopiering av en undersekvens fra et kildearray til en destinasjon:

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. Den Arrays Klasse

De Arrays klasse tilbyr også flere overbelastede metoder for å kopiere en matrise til en annen. Internt bruker den samme tilnærming som tilbys av System klasse som vi har sett tidligere. Det gir hovedsakelig to metoder, kopi av(…) og copyRangeOf (…).

La oss ta en titt på kopi av først:

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

Det er viktig å merke seg det Arrays klasse bruker Math.min (…) for å velge minimum av kildearrelengden og verdien av den nye lengdeparameteren for å bestemme størrelsen på den resulterende matrisen.

Arrays.copyOfRange () tar to parametere, ‘fra' og ‘til' i tillegg til kildearrayparameteren. Den resulterende matrisen inkluderer 'fra' indeks men 'til' indeks er ekskludert. La oss se et eksempel:

int [] array = {23, 43, 55, 12, 65, 88, 92}; int [] copiedArray = Arrays.copyOfRange (matrise, 1, 4); 
assertTrue (3 == copiedArray.length); assertTrue (copiedArray [0] == array [1]); assertTrue (copiedArray [1] == array [2]); assertTrue (copiedArray [2] == array [3]);

Begge disse metodene gjør en grunne kopi av objekter hvis de brukes på en rekke ikke-primitive objekttyper. La oss se et eksempel på en testtilfelle:

Ansatt [] copiedArray = Arrays.copyOf (ansatte, ansatte.lengde); ansatte [0] .setName (ansatte [0] .getName () + "_Changed"); assertArrayEquals (copiedArray, array);

Fordi resultatet er en grunne kopi - en endring i ansattens navn på et element i den opprinnelige matrisen forårsaket endringen i kopieringen.

Og så - hvis vi vil lage en dyp kopi av ikke-primitive typer - kan vi gå for de andre alternativene som er beskrevet i de kommende avsnittene.

4. Array Copy With Object.clone ()

Object.clone () er arvet fra Gjenstand klasse i en matrise.

La oss først kopiere en rekke primitive typer ved hjelp av klonmetoden:

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

Og et bevis på at det fungerer:

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

Ovennevnte eksempel viser at det har samme innhold etter kloning, men de har forskjellige referanser, så enhver endring i noen av dem vil ikke påvirke den andre.

På den annen side, hvis vi kloner en rekke ikke-primitive typer ved hjelp av samme metode, vil resultatene være forskjellige.

Det skaper en grunne kopi av ikke-primitive type matriseelementer, selv om klassen til det vedlagte objektet implementerer Klonbar grensesnitt og overstyrer klone () metoden fra Gjenstand klasse.

La oss se på et eksempel:

offentlig klasse Adresse implementerer Klonbar {// ... @ Override-beskyttet Objektklon () kaster CloneNotSupportedException {super.clone (); Adresse adresse = ny adresse (); address.setCity (denne.byen); returadresse; }} 

Vi kan teste implementeringen vår ved å opprette et nytt utvalg av adresser og påkalle vår klone () metode:

Adresse [] adresser = createAddressArray (); Adresse [] copiedArray = adresser.klone (); adresser [0] .setCity (adresser [0] .getCity () + "_Changed"); 
assertArrayEquals (copiedArray, adresser);

Dette eksemplet viser at enhver endring i den opprinnelige eller kopierte matrisen vil føre til endring i den andre selv når de vedlagte objektene er Klonbar.

5. Bruke Strøm API

Det viser seg at vi også kan bruke Stream API for å kopiere matriser. La oss se på et eksempel:

Streng [] strArray = {"oransje", "rød", "grønn" "}; String [] copiedArray = Arrays.stream (strArray) .toArray (String [] :: new); 

For ikke-primitive typer vil det også gjøre en grunne kopi av objekter. For å lære mer om Java 8 Streams, kan du begynne her.

6. Eksterne biblioteker

Apache Commons 3 tilbyr en nytteklasse kalt SerializationUtils som gir en klone (…) metode. Det er veldig nyttig hvis vi trenger å lage en dyp kopi av en rekke ikke-primitive typer. Den kan lastes ned herfra og dens Maven-avhengighet er:

 org.apache.commons commons-lang3 3.5 

La oss ta en titt på en testtilfelle:

offentlig klasse Medarbeidere implementerer Serialiserbare {// felt // standard getters og setters} Ansatt [] ansatte = createEmployeesArray (); Ansatt [] copiedArray = SerializationUtils.clone (ansatte); 
ansatte [0] .setName (ansatte [0] .getName () + "_Changed"); assertFalse (copiedArray [0] .getName (). tilsvarer (ansatte [0] .getName ()));

Denne klassen krever at hvert objekt skal implementere Serialiserbar grensesnitt. Når det gjelder ytelse, er det langsommere enn klonmetodene som er skrevet manuelt for hvert av objektene i objektgrafen vår å kopiere.

7. Konklusjon

I denne opplæringen så vi på de forskjellige alternativene for å kopiere en matrise i Java.

Metoden å bruke er hovedsakelig avhengig av det eksakte scenariet. Så lenge vi bruker en primitiv type matrise, kan vi bruke hvilken som helst av metodene som tilbys av System og Arrays klasser. Det skal ikke være noen forskjell i ytelse.

For ikke-primitive typer, hvis vi trenger å gjøre en dyp kopi av en matrise, kan vi enten bruke SerializationUtils eller legg til klonmetoder eksplisitt i klassene våre.

Og som alltid er eksemplene vist i denne artikkelen tilgjengelig på GitHub.