Kata pengantar
Java Cloning (klon) adalah salah satu fitur bahasa Java, tetapi jarang menggunakannya dalam praktik. Tetapi terkadang kloning lebih nyaman dan efisien.
Untuk klon, Java memiliki beberapa keterbatasan:
1. Kelas Kloning harus mengimplementasikan antarmuka yang dapat dikloning sendiri untuk menunjukkan bahwa metode Object.clone() dapat secara legal menyalin instance dari kelas ini menurut bidang. Antarmuka yang dapat dikloning sebenarnya adalah antarmuka identifikasi dan tidak memiliki metode antarmuka.
2. Kelas yang mengimplementasikan antarmuka yang dapat dikloning harus mengganti Object.clone (dilindungi) menggunakan metode publik. Tidak mungkin suatu objek untuk mengkloningnya setelah menerapkan antarmuka ini. Bahkan jika metode klon disebut secara reflektif, tidak ada jaminan bahwa itu akan berhasil.
3. Metode kloning di kelas Java.lang.Object didefinisikan sebagai berikut:
Clone objek yang dilindungi () melempar clonenotsupportedException
Membuat dan mengembalikan salinan objek ini. Ini menunjukkan bahwa itu adalah metode yang dilindungi, terlihat dalam paket yang sama.
Dengan konvensi, objek yang dikembalikan harus diperoleh dengan memanggil super.clone .
Tugas di Java
Di Java, penugasan sangat umum digunakan, tugas sederhana adalah sebagai berikut
// Jenis asli int a = 1; int b = a; // tipe referensi string [] hari kerja = string baru [5]; string [] gongzuori = hari kerja; // salin hanya referensi referensi
Dalam kode di atas.
1. Jika itu adalah tipe data asli, nilai yang dilewati oleh penugasan adalah nilai riil.
2. Jika itu adalah tipe data referensi, penugasan memberikan referensi ke objek, bukan objek.
Memahami perbedaan antara tipe data dan tipe referensi memudahkan kita untuk memahami klon.
Klon
Di Java, klon adalah proses menyalin objek yang ada ke dalam memori ke objek lain yang sama seperti itu. Kloning di Java adalah salinan domain-demi-domain.
Jika Anda ingin mendukung metode klon di Java, Anda harus terlebih dahulu mengimplementasikan antarmuka yang dapat dikloning
Kloning sebenarnya agak aneh. Ini berbeda dari antarmuka yang sering kita gunakan. Itu tidak mengandung metode apa pun di dalam, itu hanya antarmuka penandaan.
Kode sumber adalah sebagai berikut
Antarmuka publik yang dapat dikloning {}Tentang kloning, apa yang harus diperhatikan
1. Jika Anda ingin mendukung klon, Anda perlu mengimplementasikan antarmuka yang dapat dikloning
2. Jika metode klon tidak dipanggil ke antarmuka yang dapat dikloning, clonenotsupportedException akan dilemparkan.
Kemudian tulis ulang metode klon dan memodifikasinya ke tingkat akses publik
kelas statis yang dapat dikloning mengimplementasikan kloning {public int count; anak publik; @Override Public Object Clone () melempar clonenotsupportedException {return super.clone (); }}Panggil metode klon untuk menyalin objek
Clonableimp Imp1 = new clonableimp (); imp1.child = anak baru ("andy"); coba {objek obj = imp1.clone (); Clonableimp IMP2 = (clonableimp) obj; System.out.println ("Imp2.Child.name =" + Imp2.Child.name);} catch (clonenotsupportedException e) {e.printstacktrace ();}Salinan lampu
Klon yang diimplementasikan dalam kode di atas sebenarnya adalah salinan yang dangkal.
Apa yang harus Anda ketahui tentang salinan dangkal
1. Gunakan metode klon default
2. Buat salinan nilai bidang data asli
3. Hanya Salin Referensi untuk Jenis Referensi
4. Eksekusi cepat dan efisiensi tinggi
5. Data tidak dapat dipisahkan oleh 100%.
6. Jika suatu objek hanya berisi domain data asli atau domain objek yang tidak dapat diubah, disarankan untuk menggunakan salinan dangkal.
Mengenai ketidakmampuan untuk memisahkan data, kami dapat menggunakan kode ini untuk memverifikasi.
Clonableimp Imp1 = new clonableimp (); imp1.child = anak baru ("andy"); coba {objek obj = imp1.clone (); Clonableimp IMP2 = (clonableimp) obj; imp2.child.name = "bob"; System.out.println ("Main imp1.child.name =" + imp1.child.name);} catch (clonenotsupportedException e) {e.printstacktrace ();} Dalam kode di atas, kami menggunakan metode klon IMP1 untuk mengkloning IMP2, kemudian dimodifikasi imp2.child.name ke Bob, dan kemudian mencetak imp1.child.name untuk mendapatkan hasilnya.
imp1.child.name = Bob
Alasannya adalah bahwa salinan dangkal tidak mencapai pemisahan data 100%. IMP1 dan IMP2 berbagi objek anak yang sama, sehingga satu modifikasi akan mempengaruhi yang lain.
Salinan yang dalam
Salinan dalam dapat menyelesaikan masalah pemisahan data 100%. Buat saja beberapa modifikasi pada kode di atas.
1. Anak mengimplementasikan antarmuka yang dapat dikloning.
anak kelas publik mengimplementasikan nama string publik yang dapat dikloning; anak publik (nama string) {this.name = name; } @Override public string toString () {return "child [name =" + name + "]"; } @Override Objek Protected Clone () melempar clonenotsupportedException {return super.clone (); }}2. Tulis ulang metode klon dan panggil metode klon dari domain data.
kelas statis yang dapat dikloning mengimplementasikan kloning {public int count; anak publik; @Override Public Object Clone () melempar clonenotsupportedException {clonableimp obj = (clonableimp) super.clone (); obj.child = (anak) child.clone (); kembalikan obj; }} Ketika kami memodifikasi imp2.child.name lagi, itu tidak akan mempengaruhi nilai imp1.child.name , karena IMP1 dan IMP2 masing -masing memiliki objek anak sendiri, karena data 100% terisolasi.
Beberapa fitur salinan yang dalam
1. Anda perlu mengganti metode klon, tidak hanya memanggil metode kelas induk, tetapi juga memanggil metode klon atribut.
2. 100% pemisahan data antara objek asli dan objek yang dikloning tercapai
3. Jika objek memiliki atribut jenis referensi, disarankan untuk menggunakan salinan yang dalam.
4. Salinan dalam lebih memakan waktu dan kurang efisien dari salinan dangkal
Mengapa menggunakan kloning
Ini sangat penting dan umum: API perlu memberikan koleksi daftar, tetapi tidak ingin modifikasi penelepon memengaruhi perubahannya sendiri, sehingga perlu mengkloning objek untuk mencapai tujuan isolasi data.
Cloone harus dihindari sebanyak mungkin
1. Biasanya, antarmuka diimplementasikan untuk menunjukkan apa yang dapat dilakukan kelas untuk pelanggannya, sementara yang dapat dikloning hanyalah antarmuka tag, dan juga mengubah perilaku metode yang dilindungi dengan tangan di superclass. Ini adalah penggunaan antarmuka yang sangat atipikal dan tidak layak ditiru.
2. Deskripsi Javadoc dari konvensi metode klon dan metode klon yang rapuh agak ambigu, sebagai berikut: Konvensi Java SE8
Metode klon membuat dan mengembalikan salinan objek. Arti yang tepat dari salinannya tergantung pada kelas objek. Arti umum adalah bahwa untuk objek apa pun, ekspresi
x.clone() != x 为true x.clone().getClass() == x.getClass() juga mengembalikan true, tetapi tidak diperlukan x.clone().equals(x) juga mengembalikan true, tetapi tidak perlu, tetapi tidak perlu
Ekspresi kedua dan ketiga di atas dengan mudah mengembalikan false. Oleh karena itu, satu -satunya hal yang dapat menjamin true permanen adalah ekspresi satu, yaitu, kedua objek adalah objek independen.
3. Domain akhir dari objek variabel. Dalam metode kloning, jika kita perlu menyalin domain akhir dari objek variabel, sebenarnya tidak mungkin dikompilasi dan lulus karena pembatasan akhir. Oleh karena itu, untuk mengimplementasikan kloning, kita perlu mempertimbangkan untuk meninggalkan kata kunci akhir dari domain objek yang dapat berubah.
4. Keselamatan Thread Jika Anda memutuskan untuk menggunakan kelas yang aman untuk mengimplementasikan antarmuka yang dapat dikloning, Anda perlu memastikan bahwa metode klonnya disinkronkan. Metode Object.clone default. Metode tidak disinkronkan.
Secara umum, metode klon di Java sebenarnya tidak sempurna, jadi disarankan untuk menghindari menggunakannya sebanyak mungkin. Berikut adalah beberapa alternatif.
Salin Konstruktor
Menyalin objek juga dapat diimplementasikan menggunakan copy constructor.
1. Copy Constructor juga merupakan jenis konstruktor
2. Hanya satu parameter yang diterima, tipe parameter adalah kelas saat ini
3. Tujuannya adalah untuk menghasilkan objek baru dengan parameter yang sama seperti
4. Keuntungan dari Copy Constructor Over Clone Metode adalah sederhana dan mudah diimplementasikan.
Kode contoh menggunakan konstruktor salinan
mobil kelas publik {roda roda; Produsen string; mobil publik (roda roda, produsen string) {this.wheel = roda; this.manufacturer = produsen; } // Salin Mobil Publik Konstruktor (Mobil Mobil) {this (car.wheel, car.manufacturer); } roda kelas statis public {string brand; }}Perhatikan bahwa kode di atas diimplementasikan sebagai salinan dangkal. Jika Anda ingin menerapkan salinan yang dalam, silakan merujuk ke kode berikut.
// Salin Mobil Public ConstructorPublic (mobil mobil) {roda roda = roda baru (); wheel.brand = car.wheel.brand; this.wheel = roda; this.manufacturer = car.manufacturer;}Untuk kenyamanan lebih, kami juga dapat menambahkan metode statis ke kelas di atas
Public Static Car NewInstance (mobil mobil) {return new mobil (mobil);}Gunakan serial untuk mencapai salinan yang dalam
Faktanya, salinan objek yang dalam dapat dicapai dengan menggunakan serialisasi. Kode singkatnya adalah sebagai berikut
kelas publik DeepCopyExample mengimplementasikan serializable {private static final long serialversionuid = 6098694917984051357l; anak publik; Public DeepCopyExample Copy () {DeepCopyExample Copy = null; coba {bytearrayoutputStream baos = bytearrayoutputStream () baru; ObjectOutputStream oos = ObjectOutputStream baru (BAOS); oos.writeObject (ini); BytearrayInputStream bais = bytearrayInputStream baru (Baos.tobyteArray ()); ObjectInputStream OIS = ObjectInputStream baru (BAIS); copy = (DeepCopyExample) ois.readObject (); } catch (ioException e) {e.printstacktrace (); } catch (ClassNotFoundException e) {E.PrintStackTrace (); } return copy; }}Di antara mereka, anak harus mengimplementasikan antarmuka serial
anak kelas publik mengimplementasikan serializable {private static final long serialversionuid = 6832122780722711261l; name string publik = ""; anak publik (nama string) {this.name = name; } @Override public string toString () {return "child [name =" + name + "]"; }}Gunakan contoh dan kode uji
DeepCopyExample Example = New DeepCopyExample (); contoh.child = anak baru ("contoh"); DeepCopyExample copy = exampy.copy (); if (copy! = null) {copy.child.name = "disalin"; System.out.println ("example.child =" + example.child + "; copy.child =" + copy.child);} // hasil output: example.child = anak [nama = contoh]; copy.child = anak [nama = disalin]Menilai dari hasil output, memodifikasi nilai anak dari objek salin tidak mempengaruhi nilai anak dari objek contoh, yaitu, menggunakan serialisasi untuk mencapai salinan objek yang dalam.
Meringkaskan
Di atas adalah semua isi kloning di Java. Saya harap artikel ini akan membantu semua orang untuk belajar Java.