Sebelum secara resmi memasuki topik, mari kita pahami pertama-tama konsep salinan dalam dan pra-copy:
Salinan lampu:
Objek baru akan dibuat, yang memiliki salinan yang tepat dari nilai properti objek asli. Jika atribut adalah tipe dasar, nilai tipe dasar disalin; Jika atribut adalah alamat memori, alamat memori disalin, jadi jika objek mengubah alamat ini, itu akan mempengaruhi objek lain;
Salinan yang dalam:
Anda tidak hanya ingin menyalin semua nilai variabel anggota yang tidak direferensikan dari objek, tetapi Anda juga perlu membuat instance baru untuk variabel anggota dari jenis referensi dan menginisialisasi ke nilai instance parameter formal;
Setelah memahami konsep tersebut, mari kita uji apakah operasi penugasan objek biasa adalah salinan yang dalam atau salinan dangkal:
Kode Uji:
Public Class DepthCopy {public static void main (string [] args) {copy first = new copy ("hzw", 24); Salin kedua = pertama; Second.Name = "Shanxi"; System.out.println (first.name); // output shanxi}} class copy {name public string; Usia int publik; salinan publik (nama string, int usia) {this.name = name; this.age = usia; }} Dapat ditemukan bahwa setelah kedua memodifikasi nilai atribut nama ke shanxi, nilai atribut nama depan juga menjadi shanxi. Ini menunjukkan bahwa penugasan objek biasa milik salinan yang dangkal;
Setelah memahami apakah penugasan antar objek adalah salinan yang dangkal, mari kita lihat apakah kloning adalah salinan yang dalam atau salinan yang dangkal. Kode tes adalah untuk mengaktifkan objek salinan di atas untuk mengimplementasikan metode klon di antarmuka yang dapat dikloning:
Public Class DepthCopy {public static void main (string [] args) {copy first = new copy ("hzw", 24); Salin kedua = null; coba {kedua = (salin) first.clone (); } catch (clonenotsupportedException e) {e.printstacktrace (); } Second.name = "shanxi"; System.out.println (first.name); // output: hzw system.out.println (first); // output: com.hzw.day33.copy@7f39ebdb system.out.println (kedua); // output: com.hzw.day33.copy@3abb8 (kedua); // output: com.hzw.day33.copy@3abb8 (kedua); // output: com.hzw.day33.copy@3abb8); Usia int publik; salinan publik (nama string, int usia) {this.name = name; this.age = usia; } @Override Objek Protected Clone () melempar clonenotsupportedException {return super.clone (); }}Dapat dilihat bahwa objek yang diciptakan semula terlebih dahulu dan objek yang dikloning kedua adalah dua contoh, sehingga modifikasi atribut nama di urutan kedua tidak akan mempengaruhi atribut nama di pertama; Namun, kita tidak bisa hanya berpikir bahwa kloning adalah salinan yang dalam, seperti contoh berikut:
Public Class Depthcopy {public static void main (string [] args) {student student = baru siswa (95); Salin pertama = salinan baru ("HZW", 24, siswa); Salin kedua = null; coba {kedua = (salin) first.clone (); } catch (clonenotsupportedException e) {e.printstacktrace (); } Second.name = "shanxi"; Second.student.score = 60; System.out.println (first == kedua); // false system.out.println (first.student == detik.student); // true system.out.println (first.student.score); // 60}} copy copy implement clonable {public string name; Usia int publik; Mahasiswa Publik; salinan publik (nama string, usia int, siswa siswa) {this.name = name; this.age = usia; this.student = siswa; } @Override Objek Protected Clone () melempar clonenotsupportedException {return super.clone (); }} class siswa {skor int public; siswa publik (skor int) {this.score = skor; }}Pernahkah Anda melihatnya? Kami membuat kedua melalui kloning, dan jelas bahwa yang pertama dan kedua adalah dua contoh, karena output dari pertama == detik salah, tetapi objek siswa di pertama dan kedua adalah sama. Setelah memodifikasi nilai skor siswa melalui kedua, skor siswa di First juga berubah. Ini berarti bahwa siswa di yang pertama dan kedua adalah sama. Ini berarti bahwa kloning adalah salinan yang dangkal. Jika kami ingin mengimplementasikan salinan kloning yang mendalam, kami harus membiarkan objek siswa dalam objek Copy juga mengimplementasikan metode klon dalam antarmuka yang dapat dikloning, dan metode klon dalam salinan mengembalikan klon siswa, sehingga siswa dapat unik. Kode yang dimodifikasi adalah sebagai berikut:
Public Class Depthcopy {public static void main (string [] args) {student student = baru siswa (95); Salin pertama = salinan baru ("HZW", 24, siswa); Salin kedua = null; coba {kedua = (salin) first.clone (); } catch (clonenotsupportedException e) {e.printstacktrace (); } Second.name = "shanxi"; Second.student.score = 60; System.out.println (first == kedua); // false system.out.println (first.student == detik.student); // false system.out.println (first.student.score); // 95 System.out.println (Second.Student.Score); // 60}} cope coope.println (Second.student.score); // 60}} COLOP CLASSED (Second.Student.Score);/60}} class} class Usia int publik; Mahasiswa Publik; salinan publik (nama string, usia int, siswa siswa) {this.name = name; this.age = usia; this.student = siswa; } @Override Objek Protected Clone () melempar clonenotsupportedException {copy copy = (copy) super.clone (); copy.student = (student) student.clone (); kembalikan salinan; }} class siswa mengimplementasikan skor public int yang dikloning {public; siswa publik (skor int) {this.score = skor; } @Override Objek Protected Clone () melempar clonenotsupportedException {return super.clone (); }} Anda dapat melihat itu pertama dan kedua, pertama. Student dan Second.student tidak sama pada saat ini. Oleh karena itu, setelah kami memodifikasi skor siswa kedua, itu tidak mempengaruhi nilai skor siswa pada yang pertama, mencapai tujuan penyalinan yang mendalam;
Namun, jika Anda memikirkannya dengan cermat, masalahnya akan muncul. Jika ada juga atribut jenis referensi di kelas siswa dalam contoh kami di atas, seperti kelas perguruan tinggi, maka kita harus membiarkan kelas perguruan tinggi mengimplementasikan antarmuka yang dapat dikloning, dan kemudian memanggil metode klon kelas perguruan tinggi dalam metode klon di kelas siswa, dan memanggil metode klon kelas siswa dalam metode klon dari kelas copy. Saya menemukan bahwa itu hilang. Proses ini sangat rumit. Semua jenis referensi yang relevan di kelas harus mengimplementasikan antarmuka yang dapat dikloning. Saya merasa sangat merepotkan, oke, hal berikutnya adalah menjadi luar biasa.
Cara terbaik untuk menyelesaikan masalah salinan yang dalam adalah dengan menggunakan serialisasi, sehingga semua kelas tidak perlu mengimplementasikan antarmuka yang dapat dikloning, hanya membuat serialisasi dan deserialize secara langsung. Mari kita lihat.
impor java.io.file; impor java.io.fileInputStream; impor java.io.fileoutputStream; impor java.io.objectInputStream; impor java.io.objectOutputStream; impor java.io.serializable; Public Class Depthcopy {public static void main (string [] args) {College School = New College ("nongda"); Siswa Siswa = Siswa Baru (95, Sekolah); Salin salin = salinan baru ("HZW", 23, siswa); Salin lain = null; // Tunjukkan instance kelas deserialized // serialize operasi serialisasi coba {fileoutputStream fos = new FileOutputStream (file baru ("d: /copy.txt")); ObjectOutputStream oos = ObjectOutputStream baru (FOS); oos.writeObject (salin); } catch (Exception e) {E.PrintStackTrace (); } // Serialisasi operasi deserialisasi FileInputStream FIS; coba {fis = fileInputStream baru (file baru ("d: /copy.txt")); ObjectInputStream OIS = ObjectInputStream (FIS) baru; lain = (salin) ois.readObject (); } catch (Exception e) {E.PrintStackTrace (); } System.out.println (copy == lain); // false system.out.println (copy.student == another.student); // false system.out.println (copy.student.school == Other.student.school); // false lain.student.school.schoolname = " System.out.println (copy.student.school.schoolname); // nongda}} class copy mengimplementasikan serializable {public string name; Usia int publik; Mahasiswa Publik; salinan publik (nama string, usia int, siswa siswa) {this.name = name; this.age = usia; this.student = siswa; }} kelas siswa mengimplementasikan serial {public int skor; Sekolah Perguruan Tinggi Umum; siswa publik (skor int, sekolah perguruan tinggi) {this.score = skor; this.school = sekolah; }} Class College mengimplementasikan serializable {public String SchoolName; Public College (String SchoolName) {this.schoolName = SchoolName; }} Dari output, kita dapat melihat bahwa objek yang dihasilkan setelah deserialisasi adalah salinan objek asli, dan tidak memiliki hubungan apa pun dengan objek asli kecuali untuk nilai atribut yang sama. Oleh karena itu, ketika kami memodifikasi nama sekolah dari deserialisasi yang dihasilkan objek menjadi "wuda", kami tidak memodifikasi nama sekolah dari contoh asli, dan kami masih menghasilkan "nongda", jadi kami mencapai efek salinan dalam yang nyata. Namun, untuk mencapai serialisasi, semua kelas yang relevan harus mengimplementasikan antarmuka serializable, yang selalu lebih nyaman daripada mengimplementasikan antarmuka yang dapat dikloning dan metode klon.
Di atas adalah penjelasan terperinci tentang salinan Java yang dalam dan dangkal. Jika Anda membutuhkannya, silakan merujuknya.