Klonlanabilirlik neden reddedilmiyor?


139

Genellikle CloneableJava'daki arayüzün bozulduğu anlaşılmaktadır . Bundan bahsetmeyeceğim birçok neden var; diğerleri zaten yaptı. Aynı zamanda Java mimarlarının kendilerinin de konumudur .

Benim sorum şu: neden henüz kullanımdan kaldırılmadı? Çekirdek Java ekibi kırıldığına karar verdiyse, kullanımdan kaldırmayı da düşünmeliler. Bunu yapmama nedenleri nelerdir (Java 8'de hala kullanımdan kaldırılmamıştır )?


41
Bu soru "esasen fikir temelli" değildir, çünkü görünüşe göre pek çok kişi yargılama hakkına sahiptir. Sebepler hakkında bir görüşten başka bir şeyleri olmayanlar, cevap vermeye nitelikli değildir. Ancak, burada sadece yetkili bir yanıt alma şansınızın az olduğu doğrudur. Sorunuzun, çözülebilir bir sorunla ilgili olmadığı da doğrudur, bu yüzden en azından sınır dışı konu dışıdır.
Marko Topolnik

6
@MarkoTopolnik Dünyada yetkili bir cevap verebilecek bazı insanlar olduğunu kabul ediyorum, ancak burada uyguladığımız testin bu olduğuna inanmıyorum. Kapanış nedeni "bu soruya verilen cevapların neredeyse tamamen fikirlere dayanma eğiliminde olduğunu " belirtmektedir . Çok şanslı olmadıkça, burada böyle olacağını sanıyorum.
Duncan Jones

2
İşte Oracle'dan nasıl çıkarılacağı "Nasıl ve Ne Zaman" ... ( docs.oracle.com/javase/6/docs/technotes/guides/javadoc/… ) Klonlanabilir arayüz "buggy veya son derece verimsiz" durumda olabilir ama görüşlere çok açık.
Maxx

8
Hala düşünmüyoruz @Duncan fuar hakkında hüküm için söz üzerine disiplin eksikliği hakkındaki düşüncelerim dayalı answerers' parçası. Bir kullanıcı sorulma nedenini bilmiyorsa, cevaplayan tesisi konu hakkında görüş bildirmesi için kötüye kullanma yetkisi yoktur.
Marko Topolnik

4
@lexicore Evet, tam olarak --- ve bahse girebilirsiniz, bu seçeneği iyice düşünmüşlerdir ve ima yoluyla, onu reddetmemek için güçlü nedenleri olmalıdır . Kendi eleştirileri Cloneableyaygın olarak bilinmektedir.
Marko Topolnik

Yanıtlar:


120

1997'de Java Bug Veritabanına yöntem ekleme konusunda gönderilen bir hata var , bu yüzden artık işe yaramaz. "Düzeltilmez" çözünürlüğü ile kapatıldı ve gerekçe aşağıdaki gibidir:clone()Cloneable

Sun'ın Teknik İnceleme Komitesi (TRC) bu konuyu uzun süre değerlendirdi ve mevcut Klonlanabilir arayüzün belgelerini iyileştirmek dışında herhangi bir işlem yapmamanızı tavsiye etti . İşte tavsiyenin tam metni:

Varolan Java nesnesi klonlama API'leri sorunludur. Java.lang.Object üzerinde korumalı bir "klon" yöntemi vardır ve java.lang.Cloneable bir arabirim vardır. Amaç, bir sınıf başkalarının onu klonlamasına izin vermek istiyorsa, Klonlanabilir arayüzü desteklemeli ve varsayılan korumalı klon yöntemini bir genel klon yöntemiyle geçersiz kılmalıdır. Ne yazık ki, buğulanma zamanlarında uygun bir şekilde kaybedilen nedenlerden ötürü, Klonlanabilir arayüz bir klon yöntemi tanımlamaz.

Bu kombinasyon oldukça fazla karışıklığa neden olur. Bazı sınıflar Klonlanabilir'i desteklediğini iddia eder, ancak yanlışlıkla klon yöntemini desteklemeyi unutur. Geliştiriciler, Cloneable'un nasıl çalışması gerektiği ve klonun ne yapması gerektiği konusunda kafası karışık.

Maalesef, Cloneable'e bir "klon" yöntemi eklemek uyumsuz bir değişiklik olacaktır. İkili uyumluluğu bozmaz, ancak kaynak uyumluluğunu bozar. Anekdot kanıtları, pratikte sınıfların Klonlanabilir arayüzü desteklediği, ancak bir genel klon yöntemi sağlayamadığı birkaç vaka olduğunu göstermektedir. Tartışmadan sonra, TRC oybirliğiyle uyumluluk etkisi nedeniyle mevcut Klonlanabilir arayüzü DEĞİŞTİRMEMEMİZİ önerdi.

Alternatif bir teklif ise, Cloneable'nin amaçlanan amacını yansıtmak için java.lang.PubliclyCloneable yeni bir arayüz eklemekti. 5 ile 2 çoğunluk arasında TRC buna karşı çıktı. Ana endişe, bunun zaten karışık bir resme daha fazla karışıklık (yazım karışıklığı da dahil!) Ekleyeceğiydi.

TRC oybirliğiyle , nasıl kullanıldığını daha iyi tanımlamak ve uygulayıcılar için "en iyi uygulamaları" tanımlamak için mevcut Cloneable arayüzüne ek belgeler eklememizi önerdi .

Dolayısıyla, bu doğrudan kullanımdan kaldırılmayla ilgili olmasa da, Klonlanabilir "kullanımdan kaldırılmamış" olmamasının nedeni, Teknik İnceleme Komitesinin mevcut belgeleri değiştirmenin bu arayüzü kullanışlı hale getirmek için yeterli olacağına karar vermesidir . Ve öyle yaptılar. Java 1.4'e Cloneablekadar aşağıdaki gibi belgelenmiştir:

Bir sınıf, Object.clone () yöntemine, o yöntemin o sınıfın örneklerinin alandan alana kopyasını almanın yasal olduğunu belirtmek için Cloneable arabirimini uygular.

Klonlanabilir arabirimi uygulamayan örneklerin klonlanması girişimleri, CloneNotSupportedException özel durumunun atılmasına neden olur.

Cloneable arabirimi hiçbir yöntem bildirmez.

Java 1.4'den (Şubat 2002'de piyasaya sürüldü) mevcut sürüme (Java 8) kadar bu gibi görünüyor:

Sınıf, Object.clone () yöntemine, o yöntemin o sınıfın örneklerinin alandan alana kopyasını almanın yasal olduğunu belirtmek için Cloneable arabirimini uygular. Klonlanabilir arabirimi uygulamayan bir örnekte Object'in klon yöntemini çağırmak, CloneNotSupportedException özel durumunun atılmasına neden olur.

Kural olarak, bu arabirimi uygulayan sınıflar ortak bir yöntemle Object.clone'u (korunan) geçersiz kılmalıdır. Bu yöntemin geçersiz kılınmasıyla ilgili ayrıntılar için bkz. Object.clone ().

Bu arabirimin klon yöntemini içermediğini unutmayın. Bu nedenle, bir nesneyi yalnızca bu arabirimi uyguladığı gerçeği nedeniyle klonlamak mümkün değildir. Klon yöntemi yansıtıcı olarak çağrılsa bile, başarılı olacağının garantisi yoktur.


3
ve cloneyöntemin neden Objectilk sırada olduğunu biliyor musunuz ?
njzk2

8
@ njzk2 Mekanizmanın önemli bir parçası --- nesne imajı bitini biraz kopyalamak için düşük seviyeli, ekstralinguistik büyüyü yapma yöntemidir.
Marko Topolnik

3
@Unheilig Bu sihir bir kopya oluşturucu ile çoğaltamayacağınız bir şeydir: Object#clone()derleme zamanında o sınıf bilinmeden orijinal ile aynı sınıfın bir örneğini üretir.
Marko Topolnik

4
@AVolpe: Bu, "sınıfların Klonlanabilir arabirimi desteklediği, ancak genel bir klonlama yöntemi sağlamadığı" yanıtında belirtilen kaynak uyumsuzluğunu düzeltmez. Özellikle, kamuya açık olmayan bir klon yöntemi sağlayan sınıflar kırılacaktır.
Louis Wasserman

2
Güzel bir tarih. İşte hata veritabanına doğrudan bir bağlantı . Oraya biraz daha tarih ekledim ve cevabımın bazı kısımlarını alıntıladım .
Stuart Marks,

64

"Neden Cloneableitiraz edilmiyor ?" (ya da gerçekten, neden kimse için Xitiraz edilmiyor X), onları itiraz etmeye çok dikkat edilmediğidir.

Son zamanlarda kullanımdan kaldırılan çoğu şey, kaldırılacak belirli bir plan olduğu için kullanımdan kaldırılmıştır. Örneğin, addPropertyChangeListenerve removePropertyChangeListeneryöntemleri LogManager edildi Java SE 8 kullanımdan kaldırılmış Java SE 9. bunları kaldırarak niyetiyle (nedeni gereksiz yere modül bağımlılığını karmaşık olmasıdır.) Nitekim bu API'ler zaten edilmiştir erken JDK 9 kaldırıldı gelişme oluşturur. (Benzer özellik değişikliği dinleyici çağrılarının da kaldırıldığını unutmayın Pack200; bkz. JDK-8029806 .)

Böyle benzer planı için için vardır Cloneableve Object.clone().

Daha uzun bir yanıt, bu API'lara ne olacağını umabileceğiniz, kullanımdan kaldırıldıklarında platforma hangi maliyetlerin veya avantajların tahakkuk edeceği ve bir API kullanımdan kaldırıldığında geliştiricilere ne iletileceği gibi başka soruların tartışılmasını içerecektir. Bu konuyu son JavaOne konuşmam, Borç ve Kullanım Dışı Bırakma'da araştırdım . (Slaytlar bu bağlantıda mevcut; video burada .) JDK'nın kullanımdan kaldırılmasında çok tutarlı olmadığı ortaya çıkıyor. Örneğin,

  • Bu tehlikelidir ve bunu kullanmanın risklerinin farkında olmalı (: örnek Thread.stop(), Thread.resume()ve Thread.suspend()).

  • Bu, gelecekteki bir sürümde kaldırılacak

  • Bu kullanılmıyor ve farklı bir şey kullanmanız iyi bir fikir (örnek: içindeki yöntemlerin çoğu java.util.Date)

Bunların hepsi farklı anlamlardır ve bunların farklı alt kümeleri, kullanımdan kaldırılan farklı şeyler için geçerlidir. Ve bunların bazı alt kümeleri, kullanımdan kaldırılmayan şeyler için geçerlidir (ancak bu, kullanımdan kaldırılmalıdır).

Cloneableve Object.clone()tasarım kusurları olduğu ve doğru kullanılması zor olduğu için "kırılır". Bununla birlikte, clone()hala dizileri kopyalamanın en iyi yoludur ve klonlamanın, dikkatlice uygulanan sınıf örneklerinin kopyalarını oluşturmak için bazı sınırlı faydaları vardır. Klonlamayı kaldırmak, birçok şeyi bozacak uyumsuz bir değişiklik olacaktır. Bir klonlama işlemi farklı bir şekilde yeniden uygulanabilir, ancak muhtemelen daha yavaş olacaktır Object.clone().

Bununla birlikte, çoğu şey için bir kopya oluşturucu klonlamaya tercih edilir. Bu nedenle, belki Cloneablede "eski" veya "geçersiz" olarak işaretlemek veya benzer bir şey uygun olabilir. Bu, geliştiricilere muhtemelen başka bir yere bakmak istediklerini söyleyecektir, ancak klonlama mekanizmasının gelecekteki bir sürümde kaldırılabileceğini göstermez. Ne yazık ki, böyle bir işaretleyici yoktur.

Bazı şeyler durdukça, "kullanımdan kaldırılma", ortadan kaybolan az sayıdaki kullanımdan kaldırılmış özelliğin kaldırılmış olmasına rağmen, nihai olarak kaldırılması anlamına geliyor gibi görünüyor ve bu nedenle, klonlama mekanizması için kullanımdan kaldırılması gerekli görünmüyor. Belki de gelecekte geliştiricileri alternatif mekanizmalar kullanmaya yönlendiren alternatif bir işaret uygulanabilir.

GÜNCELLEME

Hata raporuna biraz ek geçmiş ekledim . JVM spesifikasyonunun erken JVM uygulayıcısı ve ortak yazarı Frank Yellin, diğer cevapta alıntılanan TRC önerisindeki "zaman sislerinde kayıp" yorumuna yanıt olarak bazı yorumlar yaptı . Burada ilgili bölümlerden alıntı yaptım; mesajın tamamı hata raporundadır.

Cloneable, Serializable ile aynı nedenden ötürü yöntem içermez. Cloneable, sınıfın desteklediği yöntemler hakkında özel bir şey söylemek yerine sınıfın bir özelliğini belirtir.

Yansımadan önce, bir Nesnenin sığ bir kopyasını oluşturmak için yerel bir yönteme ihtiyacımız vardı. Böylece Object.clone () doğdu. Ayrıca, birçok sınıfın bu yöntemi geçersiz kılmak isteyeceği ve her sınıfın klonlanmasını istemeyeceği açıktı. Bu nedenle Cloneable, programcının niyetini göstermek için doğdu.

Kısacası. Cloneable'un amacı, genel bir clone () yönteminiz olduğunu göstermek değildi. Object.clone () kullanarak klonlanmaya istekli olduğunuzu belirtmek içindi ve klon () 'u herkese açık hale getirip getirmeyeceğinize karar vermek uygulamaya bağlıydı.


3
Burada güzel bir cevap var efendim. Özellikle Object.clone()herkesin istediği için ateşe atmamanızı seviyorum , ama bunun mantıklı ve iyi şeylerini ortaya çıkarmaya hazırsınız.
icza

2
Bununla birlikte, klon () dizileri kopyalamanın en iyi yoludur ve klonlamanın, dikkatle uygulanan sınıf örneklerinin kopyalarını oluşturmak için bazı sınırlı faydaları vardır. 6428387'nin düzeltilmesiyle izlenim altındaydım, tüm kod yolları (klon, yeni / arrayCopy, Arrays.copyOf) aynı içselliğe yol açtı. Son zamanlarda bir şey değişti mi?
bestsss

2
@bestsss Ben array.clone()her zaman herhangi bir alternatif daha hızlı olduğunu sanmıyorum . API perspektifinden bakıldığında, bir diziyi çoğaltmanın en kısa yolu budur. Arrays.copyOf(array, newlen)yaklaşıyor, ancak uzunluğu değiştirmiyorsanız yedekli bir uzunluk parametresi gerektiriyor.
Stuart Marks

2
@Holger Evet, görebildiğimiz kadarıyla, 1.1'den beri bir API'nin ilk fiili kaldırılması. Ayrıca Thread.suspend()ve Thread.stop()(no-arg) 'un tehlikeli olduğunu kabul etsek de, muhtemelen kaldırılmayacak veya koşulsuz olarak bir istisna atmak için değiştirilmeyeceklerine dikkat edin - çünkü insanlar onları gerçekten kullanıyor! Muhtemelen riski üstlenmek istiyorlar. Mülk değişikliği dinleyicileri ile hafifletici faktörlerden biri, çok nadiren kullanılmasıdır, bu nedenle bunları kaldırmanın etkisi küçüktür.
Stuart Marks

2
@Holger Fasulye sadece özellikler için bir kütüphane API'sı olduğundan kavramsal java.beansolarak bağımsız hale getirilebilir java.desktop. Ne yazık ki fasulye API'sini kazarsanız AWT'de birçok bağımlılık vardır. Uygulama daha da fazla. Kesinlikle onları serbest bırakmak mümkün olabilir, ancak bunu yapmak, örneğin, günlükleri fasulyeden ayırmaktan çok daha fazla iş gibi görünüyor. Tüm modülerleştirme çabası bu çözülmeyi yapmakla ilgilidir; kuşkusuz daha fazla şey yapılabilirdi, ama sonra Jigsaw daha da uzun sürecekti.
Stuart Marks

-1

neden henüz onaylanmadı?

Çünkü JCP buna uygun görmedi ve bunu asla yapamayabilir. Onlara sor. Yanlış yerde soruyorsun.

Bu şeyi Java API'sında tutmanın nedenleri nelerdir?

Geriye dönük uyumluluk gereksinimi nedeniyle hiç kimse Java API'sından hiçbir şeyi kaldırmayacaktır. Son kez 1996/7 yıllarında AWT olay modelinde 1.0 ile 1.1 arasında değişiklik yapıldı.


17
Thread.stop(Throwable)Her zaman UnsupportedOperationExceptionarayan kişiye atmak için sözleşmesini değiştirerek (etkili bir şekilde) kaldırdılar (hedef konuya değil!).
Marko Topolnik

22
Aynı zamanda neler oldu? Thread.stop(Throwable)Java'nın işlevselliğinin kaldırılması Java 8'de gerçekleşti. Her neyse, "onlara sormak" için niteliksiz tavsiye yanlış çünkü bugün baş Java mimarının kendisi Stack Overflow'da aktif bir üye. Akışlarla ilgili soruları yanıtlamaktan rahatsız olmaz.
Marko Topolnik

13
Dahası, OP'nin sorusu, kaldırma ile ilgili değil , kullanımdan kaldırma ve açık bir şekilde kullanımdan kaldırma ile ilgili.
Marko Topolnik

17
@EJP CloneableJava API'sından kaldırılıp kaldırılmayacağını sormuyorum . Neden niçin benimsenmeyeceğini soruyorum. Ve bence burası sormak için mükemmel bir yer.
Kao

5
@VaheHarutyunyan Haykırışlarınız için teşekkür ederim, ancak Java mimarı değilim. Oracle'ın JDK grubundaki mühendisiyim.
Stuart Marks
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.