Sådan kopieres en matrix i Java

1. Oversigt

I denne hurtige artikel diskuterer vi forskellige matrixkopieringsmetoder i Java. Matrixkopi kan virke som en triviel opgave, men det kan medføre uventede resultater og programadfærd, hvis det ikke udføres omhyggeligt.

2. Den System Klasse

Lad os starte med det centrale Java-bibliotek - System.arrayCopy (); dette kopierer et array fra et kildearray til et destinationsarray, og starter kopieringshandlingen fra kildepositionen til målpositionen indtil den specificerede længde.

Antallet af elementer, der er kopieret til målgruppen, er lig med den angivne længde. Det giver en nem måde at kopiere en undersekvens af en matrix til en anden.

Hvis nogen af ​​arrayargumenterne er nul, det kaster en NullPointerException og hvis et af heltalargumenterne er negativt eller uden for området, kaster det et IndexOutOfBoundException.

Lad os se på et eksempel for at kopiere et komplet array til et andet ved hjælp af java.util.System klasse:

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

Argumenter denne metode tager er; et kildearray, startpositionen, der skal kopieres fra kildearrayet, et destinationsarray, startpositionen i destinationsarrayet og antallet af elementer, der skal kopieres.

Lad os se på et andet eksempel, der viser kopiering af en undersekvens fra et kildearray til en destination:

int [] array = {23, 43, 55, 12, 65, 88, 92}; int [] copiedArray = ny 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

Det Arrays klasse tilbyder også flere overbelastede metoder til at kopiere en matrix til en anden. Internt bruger den den samme tilgang, som System klasse, som vi har set tidligere. Det giver primært to metoder, copyOf (…) og copyRangeOf (…).

Lad os se på copyOf først:

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

Det er vigtigt at bemærke det Arrays klasse bruger Math.min (…) til valg af minimum af kildearraylængden og værdien af ​​den nye længdeparameter for at bestemme størrelsen på det resulterende array.

Arrays.copyOfRange () tager to parametre, 'fra' og 'til' ud over kildearrayparameteren. Den resulterende matrix inkluderer 'fra' indeks men 'til' indeks er ekskluderet. Lad os se et eksempel:

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

Begge disse metoder lav en lav kopi af objekter, hvis de anvendes på en række ikke-primitive objekttyper. Lad os se et eksempel på et test tilfælde:

Medarbejder [] copiedArray = Arrays.copyOf (medarbejdere, medarbejdere.længde); medarbejdere [0] .setName (medarbejdere [0] .getName () + "_Changed"); assertArrayEquals (copiedArray, array);

Fordi resultatet er en lav kopi - en ændring i medarbejdernavnet på et element i den oprindelige matrix forårsagede ændringen i kopiorrayet.

Og så - hvis vi vil lave en dyb kopi af ikke-primitive typer - kan vi gå efter de andre muligheder, der er beskrevet i de kommende sektioner.

4. Array Copy With Object.clone ()

Object.clone () er arvet fra Objekt klasse i en matrix.

Lad os først kopiere en række primitive typer ved hjælp af klonmetoden:

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

Og et bevis på, at det fungerer:

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

Ovenstående eksempel viser, at der har det samme indhold efter kloning, men de har forskellige referencer, så enhver ændring i nogen af ​​dem påvirker ikke den anden.

På den anden side, hvis vi kloner en række ikke-primitive typer ved hjælp af den samme metode, vil resultaterne være forskellige.

Det skaber en lav kopi af de ikke-primitive type array-elementer, selvom det lukkede objekts klasse implementerer Klonabel interface og tilsidesætter klon () metode fra Objekt klasse.

Lad os se på et eksempel:

offentlig klasse Adresse implementerer Klonbar {// ... @ Override beskyttet Objekt klon () kaster CloneNotSupportedException {super.clone (); Adresse adresse = ny adresse (); address.setCity (denne.by); retur adresse; }} 

Vi kan teste vores implementering ved at oprette en ny række adresser og påkalde vores klon () metode:

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

Dette eksempel viser, at enhver ændring i det originale eller kopierede array ville forårsage ændringen i den anden, selv når de lukkede objekter er Klonabel.

5. Brug af Strøm API

Det viser sig, at vi også kan bruge Stream API til at kopiere arrays. Lad os se på et eksempel:

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

For de ikke-primitive typer gør den også en lav kopi af objekter. For at lære mere om Java 8 Streams, kan du starte her.

6. Eksterne biblioteker

Apache Commons 3 tilbyder en hjælpeklasse kaldet SerializationUtils der giver en klon (…) metode. Det er meget nyttigt, hvis vi har brug for at lave en dyb kopi af en række ikke-primitive typer. Det kan downloades herfra, og dets Maven-afhængighed er:

 org.apache.commons commons-lang3 3.5 

Lad os se på en test sag:

offentlig klasse Medarbejder implementerer Serialiserbare {// felter // standard getters og setters} Medarbejder [] medarbejdere = createEmployeesArray (); Medarbejder [] copiedArray = SerializationUtils.clone (medarbejdere); 
medarbejdere [0] .setName (medarbejdere [0] .getName () + "_Changed"); assertFalse (copiedArray [0] .getName (). er lig med (medarbejdere [0] .getName ()));

Denne klasse kræver, at hvert objekt skal implementere Serialiserbar interface. Med hensyn til ydeevne er det langsommere end de klonmetoder, der er skrevet manuelt for hvert af objekterne i vores objektgraf at kopiere.

7. Konklusion

I denne vejledning så vi på de forskellige muligheder for at kopiere et array i Java.

Metoden til brug afhænger hovedsageligt af det nøjagtige scenarie. Så længe vi bruger en primitiv type array, kan vi bruge en hvilken som helst af de metoder, der tilbydes af System og Arrays klasser. Der bør ikke være nogen forskel i ydeevne.

For ikke-primitive typer, hvis vi har brug for at lave en dyb kopi af en matrix, kan vi enten bruge SerializationUtils eller tilføj klonmetoder eksplicit til vores klasser.

Og som altid er eksemplerne vist i denne artikel tilgængelige på over på GitHub.