1. Gambaran keseluruhan
Dalam artikel ringkas ini, kita akan membincangkan kaedah penyalinan array yang berbeza di Java. Salinan susunan mungkin kelihatan seperti tugas yang remeh, tetapi boleh menyebabkan hasil dan tingkah laku program yang tidak dijangka jika tidak dilakukan dengan teliti.
2. Kelas Sistem
Mari kita mulakan dengan perpustakaan inti Java - System.arrayCopy () ; ini menyalin array dari array sumber ke array tujuan, memulakan tindakan menyalin dari kedudukan sumber ke kedudukan sasaran hingga panjang yang ditentukan.
Bilangan elemen yang disalin ke array sasaran sama dengan panjang yang ditentukan. Ini menyediakan cara mudah untuk menyalin sub-urutan array ke yang lain.
Sekiranya mana-mana argumen array adalah nol, ia membuang NullPointerException dan jika ada argumen integer negatif atau berada di luar jangkauan, ia membuang 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);
Hujah kaedah ini adalah; array sumber, kedudukan permulaan untuk menyalin dari array sumber, array tujuan, kedudukan permulaan dalam array tujuan, dan jumlah elemen yang akan disalin.
Mari kita lihat contoh lain yang menunjukkan menyalin sub-urutan dari array sumber ke destinasi:
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 Susunan
The Tatasusunan kelas juga menawarkan pelbagai kaedah terlebih beban untuk menyalin array yang lain. Secara dalaman, ia menggunakan pendekatan yang sama yang disediakan oleh kelas Sistem yang telah kita lihat sebelumnya. Ini terutamanya menyediakan dua kaedah, copyOf (…) dan copyRangeOf (…) .
Mari lihat copyOf terlebih dahulu :
int[] array = {23, 43, 55, 12}; int newLength = array.length; int[] copiedArray = Arrays.copyOf(array, newLength);
Penting untuk diperhatikan bahawa kelas Arrays menggunakan Math.min (…) untuk memilih minimum panjang array sumber dan nilai parameter panjang baru untuk menentukan ukuran array yang dihasilkan.
Arrays.copyOfRange () mengambil 2 parameter, ' dari' dan ' ke' sebagai tambahan kepada parameter array sumber. Array yang dihasilkan merangkumi indeks 'dari' tetapi indeks 'ke' dikecualikan. Mari lihat contoh:
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-dua kaedah ini melakukan salinan objek yang cetek jika digunakan pada pelbagai jenis objek bukan primitif. Mari lihat contoh kes ujian:
Employee[] copiedArray = Arrays.copyOf(employees, employees.length); employees[0].setName(employees[0].getName() + "_Changed"); assertArrayEquals(copiedArray, array);
Kerana hasilnya adalah salinan cetek - perubahan pada nama pekerja dari elemen susunan asal menyebabkan perubahan dalam susunan salinan.
Oleh itu - jika kita ingin membuat salinan mendalam jenis bukan primitif - kita boleh mencari pilihan lain yang dijelaskan di bahagian yang akan datang.
4. Salin Array Dengan Object.clone ()
Object.clone () diwarisi dari kelas Objek dalam array.
Mari kita salin dahulu pelbagai jenis primitif menggunakan kaedah klon:
int[] array = {23, 43, 55, 12}; int[] copiedArray = array.clone();
Dan bukti bahawa ia berfungsi:
assertArrayEquals(copiedArray, array); array[0] = 9; assertTrue(copiedArray[0] != array[0]);
Contoh di atas menunjukkan bahawa mempunyai kandungan yang sama setelah pengklonan tetapi mereka mempunyai rujukan yang berbeza, jadi sebarang perubahan pada salah satu daripadanya tidak akan mempengaruhi yang lain.
Sebaliknya, jika kita mengklon pelbagai jenis bukan primitif menggunakan kaedah yang sama, hasilnya akan berbeza.
Ia membuat salinan cetek elemen larik jenis bukan primitif, walaupun kelas objek yang dilampirkan mengimplementasikan antara muka Cloneable dan mengganti kaedah klon () 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; } }
Kami dapat menguji pelaksanaan kami dengan membuat susunan alamat baru dan menggunakan kaedah klon () kami :
Address[] addresses = createAddressArray(); Address[] copiedArray = addresses.clone(); addresses[0].setCity(addresses[0].getCity() + "_Changed");
assertArrayEquals(copiedArray, addresses);
Contoh ini menunjukkan bahawa apa-apa perubahan pada susunan yang asli atau yang disalin akan menyebabkan perubahan pada yang lain walaupun objek yang dilampirkan dapat diklon .
5. Menggunakan Stream API
Ternyata, kami dapat 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 jenis bukan primitif, ia juga akan membuat salinan objek yang cetek. Untuk mengetahui lebih lanjut mengenai Java 8 Streams , anda boleh bermula di sini.
6. Perpustakaan Luar
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.
Kaedah yang digunakan terutamanya bergantung pada senario yang tepat. Selagi kita menggunakan susunan jenis primitif, kita dapat menggunakan salah satu kaedah yang ditawarkan oleh kelas Sistem dan Susunan . Tidak seharusnya ada perbezaan dalam prestasi.
Untuk jenis bukan primitif, jika kita perlu membuat salinan larik dalam, kita boleh menggunakan SerializationUtils atau menambahkan kaedah klon ke kelas kita secara eksplisit.
Seperti biasa, contoh yang ditunjukkan dalam artikel ini terdapat di GitHub.