Mengapa Cloneable tidak ditinggalkan?

139

Secara umum dipahami bahwa Cloneableantarmuka di Java rusak. Ada banyak alasan untuk ini, yang tidak akan saya sebutkan; yang lain sudah melakukannya. Itu juga posisi arsitek Jawa sendiri.

Karena itu pertanyaan saya adalah: mengapa belum ditinggalkan? Jika tim inti Java telah memutuskan bahwa itu rusak, maka mereka juga harus mempertimbangkan penghentian. Apa alasan mereka untuk tidak melakukannya (di Jawa 8 masih belum ditinggalkan )?

Kao
sumber
41
Pertanyaan ini bukan "terutama berdasarkan pendapat", karena banyak yang tampaknya merasa berhak untuk menilai. Mereka yang tidak memiliki alasan selain alasan tidak bisa menjawab. Namun, memang benar bahwa Anda hanya memiliki peluang kecil untuk mendapatkan jawaban resmi di sini. Benar juga bahwa pertanyaan Anda bukan tentang masalah yang Anda selesaikan, sehingga setidaknya merupakan batasan di luar topik.
Marko Topolnik
6
@MarkoTopolnik Saya setuju bahwa ada beberapa orang di dunia ini yang dapat memberikan jawaban resmi, tetapi saya tidak percaya itu adalah ujian yang kami terapkan di sini. Alasan penutupan menyatakan "jawaban untuk pertanyaan ini cenderung hampir seluruhnya didasarkan pada pendapat". Saya menduga itu akan terjadi di sini, kecuali jika kita beruntung.
Duncan Jones
2
Berikut ini adalah "Bagaimana dan Kapan" untuk mundur dari Oracle ... ( docs.oracle.com/javase/6/docs/technotes/guides/javadoc/… ) Antarmuka yang dapat dikloning mungkin jatuh dalam kasus "buggy, atau sangat tidak efisien" tetapi sangat terbuka untuk pendapat.
Maks
8
@Duncan Saya masih tidak menganggap adil untuk menghakimi pertanyaan berdasarkan asumsi saya tentang kurangnya disiplin di pihak penjawab . Jika seorang pengguna tidak tahu alasan ditanyai, ia tidak berhak menyalahgunakan fasilitas penjawab untuk menyampaikan pendapatnya tentang masalah tersebut.
Marko Topolnik
4
@lexicore Ya, tepat --- dan Anda dapat bertaruh mereka telah mempertimbangkan opsi itu dan dengan implikasi harus memiliki alasan kuat untuk tidak mencela itu. Kritik mereka sendiri Cloneabledikenal luas.
Marko Topolnik

Jawaban:

120

Ada bug yang diajukan pada tahun 1997 ke Java Bug Database tentang menambahkan clone()metode Cloneable, jadi itu tidak akan sia-sia. Itu ditutup dengan resolusi "tidak akan diperbaiki" dan pembenarannya adalah sebagai berikut:

Komite Tinjauan Teknis Sun (TRC) mempertimbangkan masalah ini secara panjang lebar dan merekomendasikan untuk tidak mengambil tindakan apa pun selain memperbaiki dokumentasi antarmuka Cloneable saat ini . Berikut ini teks lengkap dari rekomendasi:

API kloning objek Java yang ada bermasalah. Ada metode "clone" yang dilindungi di java.lang.Object dan ada antarmuka java.lang.Cloneable. Maksudnya adalah jika suatu kelas ingin memperbolehkan orang lain untuk mengkloningnya, maka itu harus mendukung antarmuka Cloneable dan mengganti metode klon terproteksi default dengan metode klon publik. Sayangnya, untuk alasan yang mudah hilang dalam kabut waktu, antarmuka Cloneable tidak mendefinisikan metode klon.

Kombinasi ini menghasilkan banyak kebingungan. Beberapa kelas mengklaim mendukung Cloneable, tetapi secara tidak sengaja lupa untuk mendukung metode clone. Pengembang bingung tentang bagaimana Cloneable seharusnya bekerja dan apa yang seharusnya dilakukan clone.

Sayangnya, menambahkan metode "clone" ke Cloneable akan menjadi perubahan yang tidak kompatibel. Itu tidak akan merusak kompatibilitas biner, tetapi itu akan merusak kompatibilitas sumber. Bukti anekdotal menunjukkan bahwa dalam praktiknya ada sejumlah kasus di mana kelas mendukung antarmuka Cloneable tetapi gagal menyediakan metode klon publik. Setelah diskusi, TRC dengan suara bulat merekomendasikan bahwa kita TIDAK boleh memodifikasi antarmuka Cloneable yang ada, karena dampak kompatibilitas.

Usulan alternatif adalah menambahkan antarmuka baru java.lang.PubliclyCloneable untuk mencerminkan tujuan Cloneable yang dimaksud. Dengan mayoritas 5 hingga 2, TRC merekomendasikan hal ini. Perhatian utama adalah bahwa ini akan menambah lebih banyak kebingungan (termasuk kebingungan ejaan!) Ke gambar yang sudah bingung.

TRC dengan suara bulat merekomendasikan bahwa kita harus menambahkan dokumentasi tambahan ke antarmuka Cloneable yang ada untuk lebih menggambarkan bagaimana itu dimaksudkan untuk digunakan dan untuk menggambarkan "praktik terbaik" untuk pelaksana.

Jadi, meskipun ini tidak secara langsung tentang usang , alasan untuk tidak membuat Cloneable "usang" adalah bahwa Technical Review Comitee memutuskan bahwa memodifikasi dokumentasi yang ada akan cukup memadai untuk membuat antarmuka ini berguna. Dan begitulah yang mereka lakukan. Hingga Java 1.4, Cloneabledidokumentasikan sebagai berikut:

Kelas mengimplementasikan antarmuka Cloneable untuk menunjukkan ke metode Object.clone () yang sah untuk metode itu untuk membuat salinan lapangan-untuk-bidang contoh turunan dari kelas itu.

Mencoba untuk mengkloning instance yang tidak mengimplementasikan antarmuka Cloneable mengakibatkan pengecualian CloneNotSupportedException dilemparkan.

Antarmuka Cloneable menyatakan tidak ada metode.

Sejak Java 1.4 (yang dirilis pada Februari 2002) hingga edisi saat ini (Java 8) kelihatannya seperti ini:

Kelas mengimplementasikan antarmuka Cloneable untuk menunjukkan ke metode Object.clone () yang sah untuk metode itu untuk membuat salinan lapangan-untuk-bidang contoh turunan dari kelas itu. Meminta metode clone Object pada contoh yang tidak mengimplementasikan antarmuka Cloneable menghasilkan pengecualian CloneNotSupportedException dilempar.

Berdasarkan konvensi, kelas yang mengimplementasikan antarmuka ini harus menimpa Object.clone (yang dilindungi) dengan metode publik. Lihat Object.clone () untuk detail tentang menimpa metode ini.

Perhatikan bahwa antarmuka ini tidak mengandung metode kloning. Oleh karena itu, tidak mungkin untuk mengkloning objek hanya berdasarkan fakta bahwa ia mengimplementasikan antarmuka ini. Bahkan jika metode klon dipanggil secara reflektif, tidak ada jaminan bahwa itu akan berhasil.

Kao
sumber
3
dan tahukah Anda mengapa clonemetode itu ada Objectdi tempat pertama?
njzk2
8
@ njzk2 Itu adalah bagian penting dari mekanisme --- ini adalah metode melakukan sihir tingkat rendah, ekstralinguistik menyalin objek gambar sedikit demi sedikit.
Marko Topolnik
3
@Unheilig Sihir itu adalah sesuatu yang tidak bisa Anda tiru dengan copy constructor: Object#clone()menghasilkan instance dari kelas yang sama seperti aslinya tanpa kelas yang diketahui pada waktu kompilasi.
Marko Topolnik
4
@ Volpe: Itu tidak akan memperbaiki ketidakcocokan sumber yang disebutkan dalam jawaban "di mana kelas mendukung antarmuka Cloneable tetapi gagal menyediakan metode klon publik." Secara khusus, kelas yang menyediakan metode klon nonpublik akan rusak.
Louis Wasserman
2
Sejarah yang bagus. Berikut ini tautan langsung ke basis data bug. Saya telah menambahkan beberapa sejarah lagi di sana, dan saya telah mengutip sebagian dari itu dalam jawaban saya .
Stuart Marks
64

Jawaban singkat untuk "mengapa tidak Cloneableusang?" (atau memang, mengapa tidak Xusang, untuk semua X) adalah bahwa tidak ada banyak perhatian yang dibayarkan untuk mencela mereka.

Sebagian besar hal yang telah ditinggalkan baru-baru ini sudah usang karena ada rencana khusus untuk menghapusnya. Sebagai contoh, addPropertyChangeListenerdan removePropertyChangeListenermetode LogManager sudah tidak digunakan lagi di Java SE 8 dengan maksud untuk menghapusnya di Java SE 9. (Alasannya adalah mereka tidak perlu memperumit saling ketergantungan modul.) Memang, API ini telah dihapus dari pengembangan JDK 9 awal. membangun. (Perhatikan bahwa panggilan pendengar perubahan properti serupa juga dihapus dari Pack200; lihat JDK-8029806 .)

Tidak ada rencana serupa untuk CloneabledanObject.clone() .

Jawaban yang lebih panjang akan melibatkan diskusi pertanyaan lebih lanjut, seperti apa yang mungkin diharapkan terjadi pada API ini, biaya atau manfaat apa yang akan bertambah dari platform jika mereka tidak digunakan lagi, dan apa yang dikomunikasikan kepada pengembang ketika API tidak digunakan lagi. Saya menjelajahi topik ini dalam pembicaraan JavaOne saya baru-baru ini, Hutang dan Penghentian . (Slide tersedia di tautan itu; video di sini .) Ternyata JDK itu sendiri tidak terlalu konsisten dalam penggunaan penghinaannya. Ini digunakan untuk mengartikan beberapa hal berbeda, termasuk misalnya,

  • Ini berbahaya dan Anda harus menyadari risiko menggunakannya (misalnya: Thread.stop(), Thread.resume(), dan Thread.suspend()).

  • Ini akan dihapus dalam rilis mendatang

  • Ini sudah usang dan merupakan ide bagus bagi Anda untuk menggunakan sesuatu yang berbeda (contoh: banyak metode di java.util.Date)

Semua ini adalah makna yang berbeda, dan himpunan bagian yang berbeda berlaku untuk hal-hal yang berbeda yang sudah usang. Dan beberapa bagian dari mereka berlaku untuk hal-hal yang tidak usang (tapi itu mungkin harus dihentikan).

Cloneabledan Object.clone()"rusak" dalam arti bahwa mereka memiliki kekurangan desain dan sulit untuk digunakan dengan benar. Namun, clone()masih merupakan cara terbaik untuk menyalin array, dan kloning memiliki kegunaan terbatas untuk membuat salinan instance kelas yang diimplementasikan dengan hati-hati. Menghapus kloning akan menjadi perubahan yang tidak kompatibel yang akan merusak banyak hal. Operasi kloning dapat diterapkan kembali dengan cara yang berbeda, tetapi mungkin akan lebih lambat daripada Object.clone().

Namun, untuk sebagian besar hal, konstruktor salinan lebih disukai daripada kloning. Jadi mungkin menandai Cloneablesebagai "usang" atau "digantikan" atau sesuatu yang serupa akan sesuai. Ini akan memberi tahu pengembang bahwa mereka mungkin ingin mencari di tempat lain, tetapi itu tidak akan menandakan bahwa mekanisme kloning mungkin dihapus dalam rilis mendatang. Sayangnya, tidak ada penanda seperti itu.

Seperti yang terjadi, "penghentian" tampaknya menyiratkan penghapusan pada akhirnya - terlepas dari kenyataan bahwa sejumlah kecil fitur yang sudah hampir punah telah dihapus - dan penghentian tampaknya tidak diperlukan untuk mekanisme kloning. Mungkin di masa depan tanda alternatif dapat diterapkan yang mengarahkan pengembang untuk menggunakan mekanisme alternatif sebagai gantinya.

MEMPERBARUI

Saya telah menambahkan beberapa riwayat tambahan ke laporan bug . Frank Yellin, pelaksana awal JVM dan penulis bersama spesifikasi JVM, membuat beberapa komentar sebagai tanggapan atas komentar "hilang dalam kabut waktu" dalam rekomendasi TRC yang dikutip dalam jawaban lain . Saya mengutip bagian yang relevan di sini; pesan lengkapnya ada di laporan bug.

Cloneable tidak memiliki metode karena alasan yang sama dengan Serializable tidak. Cloneable menunjukkan properti kelas, daripada secara khusus mengatakan apa pun tentang metode yang didukung kelas.

Sebelum refleksi, kami membutuhkan metode asli untuk membuat salinan dangkal Obyek. Maka Object.clone () lahir. Jelas juga bahwa banyak kelas ingin menimpa metode ini, dan tidak semua kelas ingin dikloning. Oleh karena itu Cloneable dilahirkan untuk menunjukkan niat programmer.

Jadi, singkatnya. Tujuan Cloneable bukan untuk menunjukkan bahwa Anda memiliki metode klon publik (). Itu untuk menunjukkan bahwa Anda bersedia untuk dikloning menggunakan Object.clone (), dan terserah implementasi untuk memutuskan apakah akan membuat clone () publik.

Stuart Marks
sumber
3
Satu jawaban yang baik Anda miliki di sini Pak. Saya terutama suka bahwa Anda tidak hanya membuang Object.clone()ke dalam api hanya karena semua orang ingin, tetapi Anda bersedia untuk bernalar dan mengemukakan hal-hal baik dari itu.
icza
2
Namun, klon () masih merupakan cara terbaik untuk menyalin array, dan kloning memiliki kegunaan terbatas untuk membuat salinan instance kelas yang diimplementasikan dengan hati-hati. Saya mendapat kesan dengan perbaikan 6428387, semua jalur kode (clone, new / arrayCopy, Arrays.copyOf) menghasilkan intrinsik yang sama. Apakah ada yang berubah baru-baru ini?
bestsss
2
@bestsss Saya tidak berpikir array.clone()selalu lebih cepat daripada alternatif apa pun. Dari perspektif API, ini adalah cara paling ringkas untuk menduplikasi array. Arrays.copyOf(array, newlen)mendekati, tetapi membutuhkan parameter panjang, yang berlebihan jika Anda tidak mengubah panjangnya.
Stuart Marks
2
@ Holger Ya sejauh yang kami bisa lihat, ini adalah penghapusan API yang sebenarnya sejak 1.1. Perhatikan juga bahwa meskipun kami sepakat bahwa Thread.suspend()dan Thread.stop()(tanpa arg) berbahaya, mereka mungkin tidak akan dihapus - atau diubah untuk melemparkan pengecualian tanpa syarat - karena orang benar-benar menggunakannya! Agaknya mereka bersedia menanggung risiko. Salah satu faktor yang meringankan dengan pendengar perubahan properti adalah bahwa mereka digunakan sangat jarang, sehingga dampak menghapusnya kecil.
Stuart Marks
2
@ Holger Secara Konseptual java.beansdapat dibuat independen java.desktopkarena kacang hanyalah API perpustakaan untuk properti. Sayangnya, jika Anda menggali API kacang, ada banyak ketergantungan pada AWT. Implementasinya bahkan lebih. Tentu saja mungkin untuk membebaskan mereka, tetapi melakukan hal itu sepertinya lebih banyak pekerjaan daripada, katakanlah, melemahkan penebangan dari kacang. Seluruh upaya modularisasi adalah tentang melakukan penguraian ini; tidak diragukan lagi banyak yang bisa dilakukan, tetapi kemudian Jigsaw akan memakan waktu lebih lama.
Stuart Marks
-1

mengapa itu belum ditinggalkan?

Karena JCP tidak cocok untuk melakukannya, dan mungkin tidak pernah melakukannya. Tanya mereka. Anda bertanya di tempat yang salah.

Apa alasan di balik menyimpan hal ini di Java API

Tidak seorang pun akan pernah menghapus apa pun dari Java API, karena persyaratan kompatibilitas ke belakang. Terakhir kali yang terjadi adalah perubahan dalam model acara AWT antara 1.0 dan 1.1 pada 1996/7.

Marquis dari Lorne
sumber
17
Mereka melakukan (secara efektif) menghapus Thread.stop(Throwable)dengan mengubah kontraknya untuk selalu melemparkan UnsupportedOperationExceptionke penelepon (bukan ke utas target!).
Marko Topolnik
22
Apa yang terjadi pada waktu yang bersamaan? Penghapusan Thread.stop(Throwable)fungsi terjadi di Java 8. Lagi pula, saran yang tidak memenuhi syarat untuk "meminta mereka" salah karena hari ini kepala arsitek Jawa sendiri adalah anggota aktif di Stack Overflow. Dia hanya tidak repot-repot menjawab apa pun kecuali pertanyaan yang terkait dengan Streaming.
Marko Topolnik
13
Selain itu, pertanyaan OP bukan tentang penghapusan , tetapi tentang penghinaan , dan jelas penghinaan telah terjadi selama ini.
Marko Topolnik
17
@ EJP Saya tidak bertanya apakah Cloneableakan dihapus dari Java API. Saya bertanya mengapa itu tidak akan hilang. Dan saya pikir ini adalah tempat yang sempurna untuk bertanya.
Kao
5
@VaheHarutyunyan Terima kasih atas teriakannya, tapi saya bukan arsitek Java. Saya seorang insinyur di grup JDK Oracle, yang mengelola hal ini.
Stuart Marks