Kloning, saya percaya semua orang telah mendengarnya. Domba kloning pertama di dunia, Dolly, menggunakan teknologi transplantasi nuklir untuk menumbuhkan individu baru dalam sel somatik dewasa mamalia, yang sangat ajaib. Bahkan, ada juga konsep kloning di Java, yaitu, untuk mewujudkan penyalinan benda.
Artikel ini akan mencoba memperkenalkan beberapa pertanyaan mendalam tentang kloning di Java, berharap dapat membantu Anda lebih memahami kloning.
Misalkan Anda ingin menyalin variabel sederhana. Sangat sederhana:
Int apel = 5; int pearls = apel;
Bukan hanya tipe int, tujuh tipe data primitif lainnya (boolean, char, byte, pendek, float, double.long) juga berlaku untuk situasi jenis ini.
Tetapi jika Anda menyalin objek, situasinya agak rumit.
Misalkan saya seorang pemula, saya akan menulis ini:
siswa kelas {nomor int pribadi; public int getNumber () {nomor kembali; } public void setNumber (int number) {this.number = number; }} tes kelas publik {public static void main (string args []) {student stu1 = new student (); Stu1.setNumber (12345); Siswa Stu2 = Stu1; System.out.println ("Siswa 1:" + Stu1.getNumber ()); System.out.println ("Siswa 2:" + Stu2.getnumber ()); }}hasil:
Siswa 1: 12345
Siswa 2: 12345
Di sini kami telah menyesuaikan kelas siswa, yang hanya memiliki satu bidang angka.
Kami membuat instance siswa baru dan menetapkan nilai ke instance STU2. (Siswa Stu2 = Stu1;)
Mari kita lihat hasil pencetakan. Sebagai seorang pemula, saya menepuk dada dan perut saya, tetapi objek itu disalin seperti ini.
Apakah ini masalahnya?
Kami mencoba mengubah bidang angka dari instance Stu2, dan kemudian mencetak hasilnya dan melihat:
Stu2.setNumber (54321); System.out.println ("Siswa 1:" + Stu1.getNumber ()); System.out.println ("Siswa 2:" + Stu2.getnumber ());hasil:
Siswa 1: 54321
Siswa 2: 54321
Ini aneh. Mengapa siswa jumlah siswa 2 berubah dan jumlah siswa siswa 1 juga berubah?
Alasannya terletak pada kalimat (Stu2 = Stu1). Tujuan dari pernyataan ini adalah untuk menetapkan referensi Stu1 ke Stu2.
Dengan cara ini, Stu1 dan Stu2 menunjuk ke objek yang sama di tumpukan memori. Seperti yang ditunjukkan pada gambar:
Jadi, bagaimana kita bisa mencapai menyalin suatu objek?
Apakah Anda ingat objek Raja dari segala usia? Ini memiliki 11 metode, dan ada dua metode yang dilindungi, salah satunya adalah metode klon.
Di Java, semua kelas diwarisi dari kelas objek dalam paket bahasa Java secara default. Periksa kode sumbernya. Anda dapat menyalin src.zip di direktori JDK Anda ke tempat lain dan mendekompresnya, dan semua kode sumber disertakan. Saya menemukan bahwa ada metode dengan klon yang dilindungi kualifikasi akses ()::
/*Membuat dan mengembalikan salinan objek ini. Makna presisi "salin" mungkin tergantung pada kelas objek. Maksud umum adalah bahwa, untuk objek apa pun x, ekspresi: 1) x.clone ()! = X akan menjadi true2) x.clone (). GetClass () == x.getClass () akan benar, tetapi ini bukan persyaratan absolut.3) X.clone (). melempar clonenotsupportedException;
Jika Anda melihat lebih dekat, itu masih merupakan metode asli. Semua orang tahu bahwa metode asli adalah kode yang diimplementasikan dalam bahasa non-java dan untuk dihubungi oleh program Java. Karena program JAVA dijalankan pada mesin virtual JVM, tidak ada cara untuk mengakses sistem yang terkait dengan sistem operasi yang mendasarinya, dan mereka hanya dapat diimplementasikan oleh bahasa yang dekat dengan sistem operasi.
Deklarasi pertama memastikan bahwa objek yang dikloning akan memiliki alokasi alamat memori yang terpisah.
Deklarasi kedua menunjukkan bahwa objek asli dan kloning harus memiliki jenis kelas yang sama, tetapi tidak wajib.
Pernyataan ketiga menunjukkan bahwa objek asli dan kloning harus sama -sama digunakan oleh metode Equals (), tetapi tidak wajib.
Karena kelas induk dari setiap kelas adalah objek, mereka semua berisi metode klon (), tetapi karena metode ini dilindungi, tidak ada yang dapat diakses di luar kelas.
Untuk menyalin objek, Anda perlu mengganti metode klon.
Mengapa mengkloning?
Mari kita pikirkan pertanyaan terlebih dahulu, mengapa Anda perlu mengkloning objek? Bukankah tidak apa -apa hanya untuk objek baru?
Jawabannya adalah: Objek yang dikloning mungkin berisi beberapa properti yang dimodifikasi, dan sifat -sifat objek baru masih merupakan nilai pada saat inisialisasi, jadi ketika objek baru diperlukan untuk menyimpan "status" objek saat ini, metode klon tergantung pada metode klon. Jadi, bukankah saya baik -baik saja bagi saya untuk menetapkan properti sementara objek ini ke objek baru saya satu per satu? Tidak apa -apa, tapi jangan membicarakannya dulu. Kedua, melalui kode sumber di atas, setiap orang telah menemukan bahwa klon adalah metode asli, yang cepat dan diimplementasikan di bagian bawah.
Izinkan saya mengingatkan Anda bahwa objek umum kami a = objek baru (); objek b; b = a; Bentuk kode ini menyalin referensi, yaitu alamat objek dalam memori, dan objek A dan B masih menunjuk ke objek yang sama.
Objek yang ditetapkan melalui metode klon ada secara independen dari objek asli.
Cara mengimplementasikan kloning
Biarkan saya pertama kali memperkenalkan dua metode kloning yang berbeda, dangkal dan kloning dalam.
Dalam bahasa Java, tipe data dibagi menjadi tipe nilai (tipe data dasar) dan tipe referensi. Jenis nilai termasuk tipe data sederhana seperti int, double, byte, boolean, char, dll. Dan jenis referensi mencakup tipe kompleks seperti kelas, antarmuka, array, dll. Perbedaan utama antara kloning dangkal dan kloning dalam adalah apakah mendukung penyalinan variabel anggota jenis referensi. Keduanya akan diperkenalkan secara rinci di bawah ini.
Langkah -langkah umum adalah (kloning dangkal):
1. Kelas yang disalin perlu mengimplementasikan antarmuka yang dapat diklonen (jika Anda tidak mengimplementasikannya, clonenotsupportedException akan dilemparkan saat memanggil metode klon). Antarmuka ini adalah antarmuka tag (tanpa metode apa pun)
2. Mengganti metode klon () dan mengatur pengubah akses ke publik. Hubungi metode super.clone () dalam metode untuk mendapatkan objek salinan yang diperlukan. (Asli adalah metode lokal)
Berikut ini adalah modifikasi dari metode di atas:
Siswa kelas mengimplementasikan kloning {private int number; public int getNumber () {return number;} public void setNumber (int number) {this.number = number;}@override public object clone () {student stu = null; coba {stu = (student) super.clone ();} catch (cloneNoTsupport {stuents) super. Stu;}} tes kelas publik {public static void main (string args []) {student stu1 = siswa baru (); stu1.setnumber (12345); siswa stu2 = (siswa) stu1.clone (); system.out.println ("student1:" + stu1.getnumber ()); Stu2.getNumber ()); Stu2.setNumber (54321); System.out.println ("Student1:" + Stu1.getNumber ()); System.out.println ("Student2:" + Stu2.getNumber ());}}}hasil:
Siswa 1: 12345
Siswa 2: 12345
Siswa 1: 12345
Siswa 2: 54321
Jika Anda tidak percaya bahwa kedua objek ini bukan objek yang sama, maka Anda dapat melihat kalimat ini:
System.out.println (Stu1 == Stu2); // PALSU
Salinan di atas disebut kloning dangkal.
Ada juga salinan dalam yang sedikit lebih kompleks:
Mari kita tambahkan kelas alamat ke kelas siswa.
Alamat kelas {private string add; public string getAdd () {return add;} public void setadd (string add) {this.add = add;}} class siswa mengimplementasikan number public {void public number; {public number; setNumber(int number) {this.number = number;}@Override public Object clone() {Student stu = null;try{stu = (Student)super.clone();}catch(CloneNotSupportedException e) {e.printStackTrace();}return stu;}}public class Test {public static void main(String args[]) {Address addr = new Alamat (); addr.setadd ("Hangzhou City"); siswa Stu1 = siswa baru (); Stu1.setNumber (123); Stu1.setAddr (addr); siswa Stu2 = (siswa) Stu1.clone (); System.out.println ("Siswa 1:" + Stu1.getnumber (); System.out.println ("Student 1:" + Stu1.getnumber (); Stu1.getAddr (). getAdd ()); System.out.println ("Siswa 2:" + Stu2.getnumber () + ", tambahkan:" + Stu2.getaddr (). getAdd ());}}hasil:
Siswa 1: 123, Alamat: Hangzhou Siswa 2: 123, Alamat: Hangzhou
Sekilas, tidak ada masalah, apakah ini masalahnya?
Kami mencoba mengubah alamat instance addr dalam metode utama.
addr.setadd ("distrik xihu"); System.out.println ("Siswa 1:" + Stu1.getNumber () + ", tambahkan:" + stu1.getAddr (). GetAdd ()); System.out.println ("Siswa 2:" + Stu2.getNumber () + ", tambahkan:" + stu2.getaddr (). GetAdd ());hasil:
Siswa 1: 123, Alamat: Hangzhou Siswa 2: 123, Alamat: Hangzhou Siswa 1: 123, Alamat: Siswa Distrik Xihu 2: 123, Alamat: Distrik Xihu
Ini aneh, mengapa alamat kedua siswa berubah?
Alasannya adalah bahwa menyalin dangkal hanya menyalin referensi variabel addr, dan tidak benar -benar membuka bagian ruang lain. Setelah menyalin nilai, kembalikan referensi ke objek baru.
Jadi, untuk mencapai objek penyalinan sejati, bukan murni menyalin referensi. Kita perlu menyalin kelas alamat dan memodifikasi metode klon. Kode lengkapnya adalah sebagai berikut:
paket ABC; Alamat kelas mengimplementasikan {private string add; public string getAdd () {return add; } public void setAdd (string add) {this.add = add; } @Override Public Object Clone () {alamat addr = null; coba {addr = (alamat) super.clone (); } catch (clonenotsupportedException e) {e.printstacktrace (); } return addr; }} class siswa mengimplementasikan klonable {private int number; alamat pribadi addr; alamat publik getAddr () {return addr; } public void setaddr (alamat addr) {this.addr = addr; } public int getNumber () {nomor kembali; } public void setNumber (int number) {this.number = number; } @Override Public Object Clone () {Student Stu = Null; coba {stu = (siswa) super.clone (); // salin dangkal} catch (clonenotsupportedException e) {e.printstacktrace (); } stu.addr = (alamat) addr.clone (); // copy return stu; }} tes kelas publik {public static void main (string args []) {alamat addr = alamat baru (); addr.setadd ("Hangzhou City"); Siswa Stu1 = Siswa Baru (); Stu1.setNumber (123); Stu1.setAddr (addr); Siswa Stu2 = (Siswa) Stu1.Clone (); System.out.println ("Siswa 1:" + Stu1.getNumber () + ", alamat:" + stu1.getAddr (). GetAdd ()); System.out.println ("Siswa 2:" + Stu2.getNumber () + ", alamat:" + stu2.getaddr (). GetAdd ()); addr.setadd ("distrik xihu"); System.out.println ("Siswa 1:" + Stu1.getNumber () + ", alamat:" + stu1.getAddr (). GetAdd ()); addr.setadd ()); System.out.println ("Siswa 2:" + Stu2.getNumber () + ", alamat:" + stu2.getaddr (). GetAdd ()); }}hasil:
Siswa 1: 123, Alamat: Hangzhou Siswa 2: 123, Alamat: Hangzhou Siswa 1: 123, Alamat: Siswa Distrik Xihu 2: 123, Alamat: Hangzhou City
Hasil ini sejalan dengan ide -ide kami.
Akhirnya, kita dapat melihat salah satu kelas di API yang mengimplementasikan metode klon:
java.util.date:
/*** Mengembalikan salinan objek ini. */ objek publik clone () {date d = null; coba {d = (date) super.clone (); if (cdate! = null) {d.cdate = (basecalendar.date) cdate.clone (); }} catch (clonenotsupportedException e) {} // tidak akan terjadi kembali d; }Kategori ini sebenarnya adalah salinan yang dalam.
Kloning dangkal dan kloning mendalam
1. Kloning dangkal
Dalam kloning dangkal, jika variabel anggota dari objek prototipe adalah jenis nilai, satu salinan akan disalin ke objek yang dikloning; Jika variabel anggota dari objek prototipe adalah jenis referensi, alamat objek referensi akan disalin ke objek yang dikloning, yaitu, variabel anggota objek prototipe dan titik objek yang dikloning ke alamat memori yang sama.
Sederhananya, dalam kloning dangkal, ketika objek disalin, hanya variabel anggota dari jenis nilai objek yang disalin dan objek anggota dari jenis referensi tidak disalin.
Dalam bahasa Java, kloning dangkal dapat diimplementasikan dengan menimpa metode klon () dari kelas objek.
2. Kloning dalam
Dalam kloning dalam, tidak peduli apakah variabel anggota dari objek prototipe adalah jenis nilai atau jenis referensi, satu salinan akan disalin ke objek yang dikloning. Kloning dalam juga menyalin semua objek yang direferensikan dari objek prototipe ke objek yang dikloning.
Sederhananya, dalam kloning dalam, kecuali untuk objek itu sendiri yang disalin, semua variabel anggota yang terkandung dalam objek juga akan disalin.
Dalam bahasa Java, jika Anda perlu menerapkan kloning mendalam, itu dapat diimplementasikan dengan menimpa metode klon () dari kelas objek, atau dapat diimplementasikan dengan serialisasi, dll.
(Jika tipe referensi berisi banyak jenis referensi, atau kelas jenis referensi dalam berisi jenis referensi, akan sangat merepotkan untuk menggunakan metode klon. Pada saat ini, kita dapat menggunakan serialisasi untuk mengimplementasikan kloning dalam objek.)
Serialisasi adalah proses penulisan objek ke aliran. Objek yang ditulis ke aliran adalah salinan objek asli, dan objek asli masih ada dalam memori. Salinan yang diimplementasikan oleh serialisasi tidak hanya dapat menyalin objek itu sendiri, tetapi juga menyalin objek anggota yang dirujuknya. Oleh karena itu, dengan membuat serial objek ke aliran dan kemudian membacanya di luar aliran, kloning dalam dapat dicapai. Perlu dicatat bahwa kelas suatu objek yang dapat mengimplementasikan serialisasi harus mengimplementasikan antarmuka serializable, jika tidak, operasi serialisasi tidak dapat diimplementasikan.
Diperpanjang
Kode antarmuka yang dapat dikloning dan antarmuka serial yang disediakan oleh bahasa Java sangat sederhana. Keduanya antarmuka kosong. Antarmuka kosong ini juga disebut antarmuka identifikasi. Tidak ada definisi metode apa pun di antarmuka identifikasi. Fungsinya adalah untuk memberi tahu JRE apakah kelas implementasi antarmuka ini memiliki fungsi tertentu, seperti apakah mereka mendukung kloning, apakah mereka mendukung serialisasi, dll.
Selesaikan masalah kloning multi-lapisan
Jika jenis referensi berisi banyak jenis referensi, atau kelas jenis referensi dalam berisi jenis referensi, akan sangat merepotkan untuk menggunakan metode klon. Pada saat ini, kita dapat menggunakan serialisasi untuk mengimplementasikan kloning yang mendalam dari objek.
kelas publik mengimplementasikan serial {private static final long serialversionuid = 369285298572941l; // Yang terbaik adalah secara eksplisit mendeklarasikan batin publik ID; // Discription: [Metode salinan dalam, membutuhkan objek dan semua sifat objek untuk diserialisasi] myclone luar publik () {luar luar = null; Coba {// Serialisasi objek ke dalam aliran, karena apa yang ditulis dalam aliran adalah salinan objek, dan objek asli masih ada di JVM. Oleh karena itu, menggunakan fitur ini, Anda dapat mencapai salinan yang dalam dari objek ByTeArrayOutputStream Baos = ByTeArrayOutputStream () baru; ObjectOutputStream oos = ObjectOutputStream baru (BAOS); oos.writeObject (ini); // Serialize aliran ke dalam objek bytearrayInputStream bais = bytearrayInputStream baru (Baos.tobyteArray ()); ObjectInputStream OIS = ObjectInputStream baru (BAIS); luar = (luar) ois.readObject (); } catch (ioException e) {e.printstacktrace (); } catch (ClassNotFoundException e) {E.PrintStackTrace (); } return luar; }}Batin juga harus menerapkan serial yang dapat diseriali, jika tidak, itu tidak dapat diserialisasi:
Kelas Publik Inner mengimplementasikan serializable {private static final long serialversionuid = 872390113109l; // Yang terbaik untuk secara eksplisit mendeklarasikan ID Public String Name = ""; public inner (name string) {this.name = name; } @Override public string toString () {return "Nilai nama dalam adalah:" + name; }}Ini juga dapat memungkinkan kedua objek untuk ada sepenuhnya secara independen di ruang memori tanpa mempengaruhi nilai satu sama lain.
Meringkaskan
Ada dua cara untuk mengimplementasikan kloning objek:
1). Mengimplementasikan antarmuka yang dapat dikloning dan mengganti metode klon () di kelas objek;
2). Menerapkan antarmuka serializable dan mengimplementasikan kloning melalui serialisasi objek dan deserialisasi, yang dapat mewujudkan kloning mendalam sejati.
Catatan: Kloning berdasarkan serialisasi dan deserialisasi bukan hanya kloning yang dalam, tetapi yang lebih penting, melalui batasan umum, tetapi dapat diperiksa apakah objek yang akan dikloning mendukung serialisasi. Cek ini dilakukan oleh kompiler dan tidak melempar pengecualian saat runtime. Solusi ini jelas lebih baik daripada kloning objek menggunakan metode klon dari kelas objek. Selalu lebih baik untuk meninggalkan masalah untuk runtime dengan mengeksposnya saat menyusun.
Di atas adalah semua penjelasan terperinci dari kode Implementasi Pemrograman Java Kode Kloning (Salin), saya harap ini akan membantu semua orang. Teman yang tertarik dapat terus merujuk ke topik terkait lainnya di situs ini. Jika ada kekurangan, silakan tinggalkan pesan untuk menunjukkannya.