Saya perlu menerapkan klon dalam di salah satu objek saya yang tidak memiliki superclass.
Apa cara terbaik untuk menangani kotak centang yang CloneNotSupportedException
dilemparkan oleh superclass (yang mana Object
)?
Seorang rekan kerja menyarankan saya untuk menanganinya dengan cara berikut:
@Override
public MyObject clone()
{
MyObject foo;
try
{
foo = (MyObject) super.clone();
}
catch (CloneNotSupportedException e)
{
throw new Error();
}
// Deep clone member fields here
return foo;
}
Ini sepertinya solusi yang baik bagi saya, tetapi saya ingin menyampaikannya ke komunitas StackOverflow untuk melihat apakah ada wawasan lain yang dapat saya sertakan. Terima kasih!
Cloneable
maka melemparAssertionError
daripada sekadar polosError
sedikit lebih ekspresif.Jawaban:
Apakah Anda benar-benar harus menggunakan
clone
? Kebanyakan orang setuju bahwa Javaclone
rusak.Josh Bloch tentang Desain - Salin Pembuat versus Kloning
Anda dapat membaca lebih banyak diskusi tentang topik ini dalam bukunya Effective Java 2nd Edition, Butir 11: Mengabaikan
clone
dengan bijaksana . Sebagai gantinya, dia merekomendasikan untuk menggunakan pembuat salinan atau pabrik penyalinan.Dia melanjutkan untuk menulis halaman halaman tentang bagaimana, jika Anda merasa harus, Anda harus menerapkan
clone
. Tapi dia menutup dengan ini:Penekanannya adalah miliknya, bukan milikku.
Karena Anda telah menjelaskan bahwa Anda tidak punya banyak pilihan selain menerapkan
clone
, inilah yang dapat Anda lakukan dalam kasus ini: pastikan ituMyObject extends java.lang.Object implements java.lang.Cloneable
. Jika demikian, maka Anda dapat menjamin bahwa Anda TIDAK PERNAH menangkapCloneNotSupportedException
. MelemparAssertionError
seperti yang disarankan beberapa tampaknya masuk akal, tetapi Anda juga dapat menambahkan komentar yang menjelaskan mengapa blok tangkap tidak akan pernah dimasukkan dalam kasus khusus ini .Atau, seperti yang juga disarankan orang lain, Anda mungkin dapat menerapkan
clone
tanpa meneleponsuper.clone
.sumber
super.clone()
dalam metode klonnya, sebuah subkelas umumnya hanya perlu mengganticlone()
jika ia menambahkan bidang baru yang isinya perlu di-clone. Jika ada superclass menggunakannew
daripadasuper.clone()
, maka semua subclass harus mengesampingkanclone()
apakah atau tidak mereka menambahkan bidang baru.Terkadang lebih mudah menerapkan konstruktor salinan:
Ini menghemat masalah penanganan
CloneNotSupportedException
, bekerja denganfinal
bidang dan Anda tidak perlu khawatir tentang jenis yang akan dikembalikan.sumber
Cara kerja kode Anda sangat mirip dengan cara "kanonis" untuk menulisnya. Tapi aku akan melempar
AssertionError
tangkapan. Ini menandakan bahwa garis itu tidak boleh dicapai.sumber
Cloneable
pada umumnya adalah ide yang rusak, seperti yang dijelaskan dalam Java Efektif. OP sudah menyatakan bahwa mereka harus menggunakanCloneable
. Jadi saya tidak tahu bagaimana lagi jawaban saya bisa diperbaiki, kecuali mungkin langsung menghapusnya.Ada dua kasus di mana surat
CloneNotSupportedException
wasiat dilemparkan:Cloneable
(dengan asumsi bahwa kloning sebenarnya pada akhirnya menolakObject
metode kloning). Jika kelas tempat Anda menulis metode ini diimplementasikanCloneable
, ini tidak akan pernah terjadi (karena sub-kelas apa pun akan mewarisinya dengan tepat).Cloneable
.Kasus terakhir tidak dapat terjadi di kelas Anda (karena Anda secara langsung memanggil metode superclass di
try
blok, bahkan jika dipanggil dari pemanggilan subclasssuper.clone()
) dan kasus sebelumnya tidak boleh karena kelas Anda harus diimplementasikan dengan jelasCloneable
.Pada dasarnya, Anda harus mencatat kesalahan dengan pasti, tetapi dalam contoh khusus ini, itu hanya akan terjadi jika Anda mengacaukan definisi kelas Anda. Jadi perlakukan itu seperti versi yang dicentang
NullPointerException
(atau serupa) - itu tidak akan pernah ditampilkan jika kode Anda berfungsi.Dalam situasi lain, Anda perlu bersiap untuk kemungkinan ini - tidak ada jaminan bahwa objek tertentu dapat digandakan, jadi saat menangkap pengecualian, Anda harus mengambil tindakan yang sesuai tergantung pada kondisi ini (lanjutkan dengan objek yang ada, ambil strategi kloning alternatif misalnya serialize-deserialize, throw an
IllegalParameterException
if your method memerlukan parameter by cloneable, dll.).Sunting : Meskipun secara keseluruhan saya harus menunjukkan bahwa ya,
clone()
sangat sulit untuk diterapkan dengan benar dan sulit bagi penelepon untuk mengetahui apakah nilai yang dikembalikan akan menjadi apa yang mereka inginkan, dua kali lipat ketika Anda mempertimbangkan klon dalam vs dangkal. Seringkali lebih baik hanya menghindari semuanya dan menggunakan mekanisme lain.sumber
super.clone()
.Gunakan serialisasi untuk membuat salinan dalam. Ini bukan solusi tercepat tetapi tidak tergantung pada tipenya.
sumber
Anda dapat mengimplementasikan konstruktor salinan yang dilindungi seperti ini:
sumber
clone()
objek yang dikembalikangetMySecondMember()
kecuali jika objek tersebut memilikipublic clone
metode.Karena sebagian besar jawaban di sini valid, saya perlu memberi tahu bahwa solusi Anda juga bagaimana pengembang Java API yang sebenarnya melakukannya. (Entah Josh Bloch atau Neal Gafter)
Berikut adalah ekstrak dari openJDK, kelas ArrayList:
Seperti yang Anda perhatikan dan orang lain sebutkan,
CloneNotSupportedException
hampir tidak ada peluang untuk dilempar jika Anda menyatakan bahwa Anda mengimplementasikanCloneable
antarmuka.Selain itu, Anda tidak perlu mengganti metode jika Anda tidak melakukan sesuatu yang baru dalam metode yang diganti. Anda hanya perlu menggantinya saat Anda perlu melakukan operasi tambahan pada objek atau Anda perlu membuatnya menjadi publik.
Pada akhirnya, yang terbaik adalah menghindarinya dan melakukannya dengan cara lain.
sumber
sumber
Hanya karena implementasi java dari Cloneable rusak, itu tidak berarti Anda tidak dapat membuatnya sendiri.
Jika tujuan OP sebenarnya adalah untuk membuat klon yang dalam, saya rasa dimungkinkan untuk membuat antarmuka seperti ini:
kemudian gunakan konstruktor prototipe yang disebutkan sebelumnya untuk mengimplementasikannya:
dan kelas lain dengan bidang objek AClass:
Dengan cara ini Anda dapat dengan mudah mengkloning objek kelas BClass dengan mudah tanpa perlu @SuppressWarnings atau kode menarik lainnya.
sumber