Jawaban:
Fakta bahwa klon dilindungi sangat meragukan - seperti fakta bahwa clone
metode tersebut tidak dideklarasikan di Cloneable
antarmuka.
Itu membuat metode ini sangat tidak berguna untuk mengambil salinan data karena Anda tidak dapat mengatakan :
if(a instanceof Cloneable) {
copy = ((Cloneable) a).clone();
}
Saya pikir desain Cloneable
sekarang sebagian besar dianggap sebagai kesalahan (kutipan di bawah). Saya biasanya ingin dapat membuat implementasi antarmuka Cloneable
tetapi tidak harus membuat antarmukaCloneable
(mirip dengan penggunaan Serializable
). Ini tidak dapat dilakukan tanpa refleksi:
ISomething i = ...
if (i instanceof Cloneable) {
//DAMN! I Need to know about ISomethingImpl! Unless...
copy = (ISomething) i.getClass().getMethod("clone").invoke(i);
}
Kutipan Dari Java Efektif Josh Bloch :
"Antarmuka yang Dapat Dikloning dimaksudkan sebagai antarmuka mixin bagi objek untuk mengiklankan bahwa mereka mengizinkan kloning. Sayangnya gagal untuk memenuhi tujuan ini ... Ini adalah penggunaan antarmuka yang sangat tidak lazim dan bukan untuk ditiru ... Untuk mengimplementasikan antarmuka agar memiliki efek apa pun pada kelas, ia dan semua kelas supernya harus mematuhi protokol yang cukup kompleks, tidak dapat diterapkan, dan sebagian besar tidak berdokumen "
Serializable
- terserah pada implementasi untuk memutuskan apakah akan diimplementasikan Serializable
. Saya memperluas ini menjadi Cloneable
- ini bukan sesuatu yang harus diperluas antarmuka - tetapi implementasi antarmuka gratis Cloneable
. Masalahnya adalah, jika Anda memiliki parameter tipe antarmuka, Anda akan bertanya apakah itu dapat di-clone; tapi kemudian Anda tidak bisa benar-benar mengkloningnya!
Antarmuka Clonable hanyalah penanda yang mengatakan bahwa kelas dapat mendukung kloning. Metode ini dilindungi karena Anda tidak boleh memanggilnya pada objek, Anda dapat (dan harus) menimpanya sebagai publik.
Dari Matahari:
Di kelas Object, metode clone () dinyatakan dilindungi. Jika semua yang Anda lakukan adalah mengimplementasikan Cloneable, hanya subclass dan anggota dari paket yang sama yang dapat memanggil clone () pada objek. Untuk mengaktifkan kelas apa pun dalam paket apa pun untuk mengakses metode clone (), Anda harus menimpanya dan mendeklarasikannya ke publik, seperti yang dilakukan di bawah ini. (Ketika Anda mengganti sebuah metode, Anda bisa membuatnya kurang privat, tapi tidak lebih privat. Di sini, metode clone () yang dilindungi di Object sedang diganti sebagai metode publik.)
Set
clone
dilindungi karena itu adalah sesuatu yang harus diganti sehingga khusus untuk kelas saat ini. Meskipun dimungkinkan untuk membuat clone
metode publik yang akan mengkloning objek apa pun, ini tidak akan sebagus metode yang ditulis khusus untuk kelas yang membutuhkannya.
Metode Clone tidak dapat langsung digunakan pada objek apa pun, itulah sebabnya metode ini dimaksudkan untuk diganti oleh subclass.
Tentu saja itu bisa publik dan hanya membuang pengecualian yang sesuai saat kloning tidak memungkinkan, tapi saya pikir itu akan menyesatkan.
Cara kloning diterapkan saat ini membuat Anda berpikir tentang mengapa Anda ingin menggunakan kloning, dan bagaimana Anda ingin objek Anda dikloning.
Ini dilindungi karena implementasi default melakukan salinan dangkal berdasarkan anggota dari semua bidang (termasuk pribadi), menghindari konstruktor . Ini bukanlah sesuatu yang mungkin didesain untuk ditangani oleh objek (misalnya, mungkin melacak instance objek yang dibuat dalam daftar bersama, atau yang serupa).
Untuk alasan yang sama, implementasi default clone()
akan melempar jika objek yang dipanggil tidak diimplementasikan Cloneable
. Ini adalah operasi yang berpotensi tidak aman dengan konsekuensi yang luas, dan oleh karena itu penulis kelas harus ikut serta secara eksplisit.
Dari javadoc cloneable.
* By convention, classes that implement this interface (cloneable) should override
* <tt>Object.clone</tt> (which is protected) with a public method.
* See {@link java.lang.Object#clone()} for details on overriding this
* method.
* Note that this interface does <i>not</i> contain the <tt>clone</tt> method.
* Therefore, it is not possible to clone an object merely by virtue of the
* fact that it implements this interface. Even if the clone method is invoked
* reflectively, there is no guarantee that it will succeed.
Jadi Anda dapat memanggil klon pada setiap objek tetapi ini akan memberi Anda sebagian besar waktu bukan hasil yang Anda inginkan atau pengecualian. Tetapi hanya dianjurkan jika Anda menerapkan cloneable.
IMHO sesederhana ini:
#clone
tidak boleh dipanggil pada objek yang tidak dapat digandakan, oleh karena itu tidak dipublikasikan#clone
harus dipanggil oleh subclass ob Object
yang mengimplementasikan Cloneable untuk mendapatkan salinan dangkal dari kelas yang tepatApa cakupan yang tepat untuk metode yang dapat dipanggil oleh subkelas, tetapi tidak oleh kelas lain?
Itu protected
.
Kelas yang mengimplementasikan Cloneable
tentu saja akan membuat metode ini menjadi publik sehingga bisa dipanggil dari kelas lain.
Metode Clone () memiliki pemeriksaan internal 'instance Cloneable or not'. Ini adalah bagaimana tim Java mungkin berpikir akan membatasi penggunaan metode clone () yang tidak tepat. Metode clone () dilindungi yaitu hanya diakses oleh subclass. Karena objek adalah kelas induk dari semua sub kelas, maka metode Clone () dapat digunakan oleh semua kelas secara tidak langsung jika kita tidak memiliki pemeriksaan di atas dari 'instance of Cloneable'. Inilah alasan mengapa tim Java mungkin berpikir untuk membatasi penggunaan clone () yang tidak tepat dengan memeriksa metode clone () 'is it instance of Cloneable'.
Karenanya kelas apa pun yang mengimplementasikan cloneable dapat menggunakan metode clone () dari kelas Object.
Juga karena dibuat dilindungi, ini tersedia hanya untuk sub kelas yang mengimplementasikan antarmuka yang dapat digandakan. Jika kita ingin membuatnya menjadi publik, metode ini harus diganti oleh sub kelas dengan implementasinya sendiri.
Ya, masalah yang sama yang saya temui. Tetapi saya menyelesaikannya dengan menerapkan kode ini
public class Side implements Cloneable {
public Side clone() {
Side side = null;
try {
side = (Side) super.clone();
} catch (CloneNotSupportedException e) {
System.err.println(e);
}
return side;
}
}
Seperti yang dikatakan sebelumnya.
Yah, juga para pengembang matahari hanyalah manusia, dan mereka memang membuat kesalahan besar untuk menerapkan metode klon sebagai dilindungi, kesalahan yang sama saat mereka menerapkan metode klon yang tidak berfungsi di ArrayList! Jadi, secara umum, ada kesalahpahaman yang jauh lebih dalam dari programmer Java yang berpengalaman tentang metode klon.
Namun, saya baru-baru ini menemukan solusi cepat dan mudah untuk menyalin objek apapun dengan semua isinya, tidak peduli bagaimana itu dibuat dan apa isinya, lihat jawaban saya di sini: Bug dalam menggunakan Object.clone ()
Sekali lagi, kerangka kerja Java JDK menunjukkan pemikiran yang brilian:
Antarmuka yang dapat digandakan tidak berisi "klon T publik ();" metode karena ia bertindak lebih seperti atribut (mis. Serializable) yang memungkinkan sebuah instance untuk dikloning.
Tidak ada yang salah dengan desain ini karena:
Object.clone () tidak akan melakukan apa yang Anda inginkan dengan kelas yang ditentukan khusus Anda.
Jika Anda memiliki Myclass mengimplementasikan Cloneable => Anda menimpa clone () dengan "public MyClass clone ()"
Jika Anda memiliki MyInterface extends Cloneable dan beberapa MyClasses mengimplementasikan MyInterface: cukup definisikan "public MyInterface clone ();" di antarmuka dan setiap metode yang menggunakan objek MyInterface akan dapat mengkloningnya, apa pun kelas MyClass-nya.