Saya sedang mencari beberapa tutorial yang menjelaskan tentang Java Cloneable
, tetapi tidak mendapatkan tautan yang bagus, dan Stack Overflow menjadi pilihan yang lebih jelas.
Saya ingin mengetahui yang berikut ini:
Cloneable
artinya kita dapat memiliki tiruan atau salinan objek, dengan mengimplementasikanCloneable
antarmuka. Apa keuntungan dan kerugiannya?- Bagaimana kloning rekursif terjadi jika objek adalah objek komposit?
Jawaban:
Hal pertama yang harus Anda ketahui
Cloneable
adalah - jangan menggunakannya.Sangat sulit untuk menerapkan kloning dengan
Cloneable
benar, dan usaha itu tidak sepadan.Alih-alih itu gunakan beberapa opsi lain, seperti apache-commons
SerializationUtils
(deep-clone) atauBeanUtils
(shallow-clone), atau cukup gunakan copy-constructor.Lihat di sini untuk pandangan Josh Bloch tentang kloning dengan
Cloneable
, yang menjelaskan banyak kelemahan dari pendekatan ini. ( Joshua Bloch adalah seorang karyawan Sun, dan memimpin pengembangan berbagai fitur Java.)sumber
static
metode di antarmuka, jadi berikan sajastatic WhatEverTheInterface copy(WhatEverTheInterface initial)
? tetapi saya bertanya-tanya apa yang diberikan ini, karena Anda menyalin bidang dari objek saat kloning, tetapi antarmuka hanya mendefinisikan metode. peduli untuk menjelaskan?Cloneable sendiri sayangnya hanyalah sebuah antarmuka-penanda, yaitu: ia tidak mendefinisikan metode clone ().
Apa yang dilakukannya, adalah mengubah perilaku metode Object.clone () yang dilindungi, yang akan memunculkan CloneNotSupportedException untuk kelas yang tidak mengimplementasikan Cloneable, dan melakukan salinan dangkal berdasarkan anggota untuk kelas yang melakukannya.
Meskipun ini adalah perilaku yang Anda cari, Anda masih perlu menerapkan metode clone () Anda sendiri untuk membuatnya menjadi publik.
Saat mengimplementasikan clone () Anda sendiri, idenya adalah memulai dengan objek yang dibuat oleh super.clone (), yang dijamin memiliki kelas yang benar, dan kemudian melakukan populasi tambahan bidang jika salinan dangkal tidak sesuai. kamu ingin. Memanggil konstruktor dari clone () akan menjadi masalah karena hal ini akan merusak pewarisan jika subclass ingin menambahkan logika tambahannya yang dapat digandakan; jika itu memanggil super.clone () itu akan mendapatkan objek dari kelas yang salah dalam kasus ini.
Pendekatan ini mengabaikan logika apa pun yang mungkin ditentukan dalam konstruktor Anda, yang berpotensi menimbulkan masalah.
Masalah lainnya adalah setiap subclass yang lupa menimpa clone () akan secara otomatis mewarisi salinan dangkal default, yang kemungkinan besar bukan yang Anda inginkan jika statusnya bisa berubah (yang sekarang akan dibagikan antara sumber dan salinan).
Sebagian besar pengembang tidak menggunakan Cloneable karena alasan ini, dan cukup terapkan konstruktor salinan sebagai gantinya.
Untuk informasi lebih lanjut dan potensi jebakan Cloneable, saya sangat merekomendasikan buku Java Efektif oleh Joshua Bloch
sumber
Jadi, gunakan Cloneable dengan bijaksana. Ini tidak memberi Anda manfaat yang cukup dibandingkan dengan upaya yang perlu Anda terapkan untuk melakukan segalanya dengan benar.
sumber
Kloning adalah paradigma pemrograman dasar. Fakta bahwa Java mungkin telah menerapkannya dengan buruk dalam banyak hal tidak mengurangi kebutuhan kloning sama sekali. Dan, mudah untuk mengimplementasikan kloning yang akan bekerja sesuai keinginan Anda, dangkal, dalam, campuran, apa pun. Anda bahkan dapat menggunakan nama clone untuk fungsi tersebut dan tidak mengimplementasikan Cloneable jika Anda mau.
Misalkan saya memiliki kelas A, B, dan C, di mana B dan C berasal dari A. Jika saya memiliki daftar objek tipe A seperti ini:
Sekarang, daftar itu bisa berisi objek tipe A, B, atau C. Anda tidak tahu apa tipe objek itu. Jadi, Anda tidak dapat menyalin daftar seperti ini:
Jika objek sebenarnya tipe B atau C, Anda tidak akan mendapatkan salinan yang benar. Dan, bagaimana jika A abstrak? Sekarang, beberapa orang menyarankan ini:
Ini adalah ide yang sangat, sangat buruk. Bagaimana jika Anda menambahkan tipe turunan baru? Bagaimana jika B atau C ada dalam paket lain dan Anda tidak memiliki akses ke mereka di kelas ini?
Apa yang ingin Anda lakukan adalah:
Banyak orang telah menunjukkan mengapa implementasi dasar Java dari klon bermasalah. Tapi, mudah diatasi dengan cara ini:
Di kelas A:
Di kelas B:
Di kelas C:
Saya tidak menerapkan Cloneable, hanya menggunakan nama fungsi yang sama. Jika Anda tidak menyukainya, beri nama lain.
sumber
A) Tidak banyak keuntungan dari klon dibandingkan dengan konstruktor salinan. Mungkin yang terbesar adalah kemampuan untuk membuat objek baru dengan tipe dinamis yang sama persis (dengan asumsi tipe yang dideklarasikan dapat digandakan dan memiliki metode klon publik).
B) Klon default membuat salinan dangkal, dan itu akan tetap menjadi salinan dangkal kecuali implementasi klon Anda mengubahnya. Ini bisa jadi sulit, terutama jika kelas Anda memiliki bidang akhir
Bozho benar, kloning mungkin sulit dilakukan dengan benar. Konstruktor / pabrik fotokopi akan melayani sebagian besar kebutuhan.
sumber
Apa kerugian dari Cloneable?
Kloning sangat berbahaya jika objek yang Anda salin memiliki komposisi. Anda perlu memikirkan kemungkinan efek samping di bawah ini karena kloning membuat salinan dangkal:
Katakanlah Anda memiliki satu objek untuk menangani manipulasi terkait db. Katakanlah, objek itu memiliki
Connection
objek sebagai salah satu propertinya.Jadi, ketika seseorang membuat tiruan dari
originalObject
, Objek yang sedang dibuat, katakanlah ,cloneObject
. Di sini,originalObject
dancloneObject
pegang referensi yang sama untukConnection
objek.Katakanlah
originalObject
menutupConnection
objek, jadi sekarangcloneObject
kehendak tidak akan berfungsi karenaconnection
objek dibagikan di antara mereka dan itu sebenarnya ditutup olehoriginalObject
.Masalah serupa dapat terjadi jika katakanlah Anda ingin mengkloning objek yang memiliki IOStream sebagai properti.
Bagaimana kloning rekursif terjadi jika objek adalah objek komposit?
Cloneable melakukan penyalinan dangkal. Artinya, data objek asli dan objek kloning akan mengarah ke referensi / memori yang sama. Sebaliknya dalam kasus deep copy, data dari memori objek asli disalin ke memori objek kloning.
sumber
Cloneable
tidak melakukan penyalinan,Object.clone
tidak. "Data dari memori objek asli disalin ke memori objek kloning" persis apa yangObject.clone
dilakukannya. Anda perlu berbicara tentang memori objek yang direferensikan untuk mendeskripsikan penyalinan mendalam.