Cara Menyalin Array di Java

1. Ikhtisar

Dalam artikel singkat ini, kita akan membahas metode penyalinan array yang berbeda di Java. Salinan array mungkin tampak seperti tugas yang sepele, tetapi dapat menyebabkan hasil yang tidak diharapkan dan perilaku program jika tidak dilakukan dengan hati-hati.

2. Kelas Sistem

Mari kita mulai dengan pustaka inti Java - System.arrayCopy () ; ini menyalin larik dari larik sumber ke larik tujuan, memulai tindakan salin dari posisi sumber ke posisi target hingga panjang yang ditentukan.

Jumlah elemen yang disalin ke larik target sama dengan panjang yang ditentukan. Ini menyediakan cara mudah untuk menyalin sub-urutan array ke yang lain.

Jika salah satu argumen array nol, itu melempar NullPointerException dan jika salah satu argumen integer negatif atau di luar jangkauan, melempar IndexOutOfBoundException .

Mari kita lihat contoh untuk menyalin array lengkap ke yang lain menggunakan kelas java.util.System :

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

Argumen yang diambil metode ini adalah; larik sumber, posisi awal untuk menyalin dari larik sumber, larik tujuan, posisi awal dalam larik tujuan, dan jumlah elemen yang akan disalin.

Mari kita lihat contoh lain yang menunjukkan menyalin sub-urutan dari larik sumber ke tujuan:

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. Kelas Array

Kelas Array juga menawarkan beberapa metode kelebihan beban untuk menyalin larik ke yang lain. Secara internal, ini menggunakan pendekatan yang sama yang disediakan oleh kelas Sistem yang telah kita lihat sebelumnya. Ini terutama menyediakan dua metode, copyOf (…) dan copyRangeOf (…) .

Mari kita lihat copyOf terlebih dahulu :

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

Penting untuk dicatat bahwa kelas Array menggunakan Math.min (…) untuk memilih minimum panjang larik sumber dan nilai parameter panjang baru untuk menentukan ukuran larik yang dihasilkan.

Arrays.copyOfRange () mengambil 2 parameter, ' from' dan ' to' selain parameter larik sumber. Array yang dihasilkan menyertakan indeks ' dari' tetapi indeks 'ke' dikecualikan. Mari kita lihat contohnya:

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

Kedua metode ini melakukan salinan objek dangkal jika diterapkan pada larik tipe objek non-primitif. Mari kita lihat contoh kasus uji:

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

Karena hasilnya adalah salinan dangkal - perubahan nama karyawan dari elemen array asli menyebabkan perubahan dalam array salinan.

Jadi - jika kita ingin membuat salinan mendalam dari tipe non-primitif - kita bisa mencari opsi lain yang dijelaskan di bagian mendatang.

4. Salinan Array Dengan Object.clone ()

Object.clone () diwarisi dari kelas Object dalam sebuah array.

Pertama-tama, salin array tipe primitif menggunakan metode klon:

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

Dan bukti bahwa itu berhasil:

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

Contoh di atas menunjukkan bahwa memiliki konten yang sama setelah kloning tetapi memiliki referensi yang berbeda, jadi setiap perubahan di salah satunya tidak akan memengaruhi yang lain.

Di sisi lain, jika kita mengkloning array tipe non-primitif menggunakan metode yang sama, maka hasilnya akan berbeda.

Ini membuat salinan dangkal dari elemen array tipe non-primitif, bahkan jika kelas objek tertutup mengimplementasikan antarmuka Cloneable dan menimpa metode clone () dari kelas Objek .

Mari kita lihat contohnya:

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

Kita dapat menguji implementasi kita dengan membuat array alamat baru dan menggunakan metode clone () kita :

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

Contoh ini menunjukkan bahwa setiap perubahan dalam larik asli atau yang disalin akan menyebabkan perubahan pada larik lainnya bahkan saat objek tertutup dapat dikloning .

5. Menggunakan Stream API

Ternyata, kita bisa menggunakan Stream API untuk menyalin array juga. Mari kita lihat contohnya:

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

Untuk tipe non-primitif, itu juga akan melakukan salinan objek yang dangkal. Untuk mempelajari lebih lanjut tentang Java 8 Streams , Anda dapat mulai di sini.

6. Perpustakaan Eksternal

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.

Metode yang digunakan terutama bergantung pada skenario yang sebenarnya. Selama kita menggunakan array tipe primitif, kita dapat menggunakan salah satu metode yang ditawarkan oleh kelas Sistem dan Array . Seharusnya tidak ada perbedaan dalam performa.

Untuk tipe non-primitif, jika kita perlu melakukan salinan mendalam dari sebuah array kita bisa menggunakan SerializationUtils atau menambahkan metode kloning ke kelas kita secara eksplisit.

Dan seperti biasa, contoh yang ditampilkan di artikel ini tersedia di lebih dari GitHub.