Clone () yöntemi neden java.lang.Object'te korunuyor?


Yanıtlar:


107

Klonun korunduğu gerçeği, cloneyöntemin Cloneablearayüzde bildirilmediği gerçeği gibi son derece şüphelidir .

Verilerin kopyalarını almak için yöntemi oldukça kullanışsız hale getirir çünkü şunu söyleyemezsiniz :

if(a instanceof Cloneable) {
    copy = ((Cloneable) a).clone();
}

Tasarımının Cloneableartık büyük ölçüde bir hata olarak kabul edildiğini düşünüyorum (aşağıda alıntı). Normalde bir arayüzün uygulamalarını yapabilmeyi isterdim Cloneableama mutlakaCloneable arayüzü yapmam (kullanımına benzer Serializable). Bu, derinlemesine düşünmeden yapılamaz:

ISomething i = ...
if (i instanceof Cloneable) {
   //DAMN! I Need to know about ISomethingImpl! Unless...
   copy = (ISomething) i.getClass().getMethod("clone").invoke(i);
}

Josh Bloch'un Etkili Java'sından Alıntı :
"Klonlanabilir arabirim, nesnelerin klonlamaya izin verdiklerinin reklamını yapmaları için bir mixin arabirimi olarak tasarlandı. Ne yazık ki bu amaca hizmet etmiyor ... Bu, taklit edilecek bir arabirim değil, oldukça alışılmadık bir arabirim kullanımıdır ... Arayüzün bir sınıf üzerinde herhangi bir etkiye sahip olması için, o ve tüm üst sınıflarının oldukça karmaşık, uygulanamaz ve büyük ölçüde belgelenmemiş bir protokole uyması gerekir "


2
Nesne Cloneable değilse, Object'in clone () CloneNotSupportedException oluşturur. Dolayısıyla, super.clone () işlevini çağıracaksanız (Object.clone () çağrılırsa) Cloneable olmanız gerekir. Serializable'ı uygulamadan bir nesnenin nasıl serileştirilebileceğini anlamıyorum.
Steve Kuo

1
"Cloneable'ın tasarımının artık büyük ölçüde bir hata olarak görüldüğünü düşünüyorum." [kaynak belirtilmeli]
Kevin Panko

Üzgünüm - bunu ima etmiyordum. Ben sadece "iyi" tasarımın bir arabirimi genişletmek olmadığını ima ediyordum Serializable- uygulanıp uygulanmayacağına karar vermek uygulamalara bağlıdır Serializable. Bunu Cloneablegenişletiyordum - bir arayüzün genişletmesi gereken bir şey değil - ama bir arayüzün uygulanması özgürdür Cloneable. Sorun şu ki, arayüz türünde bir parametreniz varsa, ona klonlanabilir olup olmadığını sormanız; ama o zaman onu gerçekten klonlayamazsınız!
oxbow_lakes

6
@Kevin - Josh Bloch'un etkili Java pp45. "Klonlanabilir arayüz, nesnelerin klonlamaya izin verdiklerinin reklamını yapmak için bir mixin arayüzü olarak tasarlandı. Ne yazık ki bu amaca hizmet
etmiyor

Ayrıca aynı sayfada: "Bu, taklit edilecek bir arayüz değil, son derece alışılmadık bir arayüz kullanımıdır" ve "Arayüzün bir sınıf üzerinde herhangi bir etkiye sahip olması için, onun ve tüm üst sınıflarının oldukça karmaşık bir uygulamaya uyması gerekir , uygulanamaz ve büyük ölçüde belgelenmemiş protokol "
oxbow_lakes

30

Klonlanabilir arayüz, sınıfın klonu destekleyebileceğini belirten bir işarettir. Yöntem korumalıdır çünkü onu nesne üzerinde çağırmamalısınız, onu genel olarak geçersiz kılabilirsiniz (ve yapmalısınız).

Güneşten:

Object sınıfında, clone () yöntemi korumalı olarak bildirilir. Yaptığınız tek şey Cloneable'ı uygulamaksa, yalnızca aynı paketin alt sınıfları ve üyeleri nesnede clone () işlevini çağırabilir. Herhangi bir paketteki herhangi bir sınıfın clone () yöntemine erişmesini sağlamak için, aşağıda yapıldığı gibi onu geçersiz kılmanız ve genel olarak ilan etmeniz gerekir. (Bir yöntemi geçersiz kıldığınızda, onu daha az özel yapabilir ancak daha özel yapamazsınız. Burada, Object'teki korumalı clone () yöntemi genel bir yöntem olarak geçersiz kılınır.)


Hangisi iyi, karışıma arayüzler getirene kadar - bilinmeyen bir uygulamayı klonlamaya çalışınSet
oxbow_lakes

@oxbow_lakes: ama belki bazı Set uygulamaları klonlanamaz
newacct

3
Klonlanabilir arabirimi uygulamayan hiçbir şeyi klonlayamazsınız - "Bu sınıf düzgün bir şekilde klonlanabilir" yazan bir işarettir - Serializable arabirime çok benzer. Bu arada, iyi çalışan serileştirme yoluyla sınıfları klonlamanın bir yolu var - google "java serileştirme klonu" gibi bir şey ve muhtemelen nesnenizin derin bir kopyasını almanın birkaç yolunu bulacaksınız.
Bill K

4
Klonlanabilir arabirimi uygulamayan hiçbir şeyi klonlayamazsınız, ancak bir şeyin Klonlanabilir arabirimi uygulaması onu klonlayabileceğiniz anlamına gelmez.
Michael Myers

1
@BuckCherry toString'in varsayılan bir uygulaması vardır, eğer onu çağırırsanız iyi bir şey olur ve bir dizgeyi geri alırsınız. eşittir varsayılan bir uygulamaya sahiptir (== ile aynı). Klonun varsayılan bir uygulaması olamaz. Eğer onu uygulamamış bir nesnede klon çağırırsanız, makul bir davranış elde edemezsiniz. Klonlama karmaşıktır ve gerçekten otomatik olarak yapılamaz (varsayılan oluşturuculara sahip olmayan bazı nesnelerin genel olarak klonlanması imkansız olabilir), bu nedenle varsayılan olarak biraz daha güvenli hale getirir. Sanırım bunu Object üzerine koymak gerekli olmayabilirdi.
Bill K

7

clonekorumalıdır, çünkü mevcut sınıfa özgü olması için geçersiz kılınması gereken bir şeydir. cloneHerhangi bir nesneyi klonlayacak bir genel yöntem oluşturmak mümkün olsa da, bu, özellikle ona ihtiyaç duyan sınıf için yazılmış bir yöntem kadar iyi olmayacaktır.


ama bunun için neden korunmalı?
Janusz

3
Korumalıdır, böylece nesnedeki birini kullanmazsınız (yine de bir istisna atar). Bir sınıfta onu geçersiz kılmanızı istiyorlar, sonra onu herkese açık hale getiriyorsunuz. (aşağıda da birkaç kez cevapladı)
Bill K

1
Ve aşağıdaki noktaya göre arayüzler düşünüldüğünde faydasız
oxbow_lakes

geçersiz kılınması gerektiği çok açık değil, o zaman soyut olmalı ve sonra Nesne Sınıfında olmamalı, neden böyle olduğunu anlamaya çalışıyorum.
Kumar Abhishek

4

Clone yöntemi doğrudan herhangi bir nesne üzerinde kullanılamaz, bu nedenle alt sınıf tarafından geçersiz kılınması amaçlanmıştır.

Tabii ki halka açık olabilir ve klonlama mümkün olmadığında uygun bir istisna yapabilir, ancak bunun yanıltıcı olacağını düşünüyorum.

Şu anda klonun uygulanma şekli, neden klon kullanmak istediğinizi ve nesnenizin nasıl klonlanmasını istediğinizi düşünmenizi sağlar.


2

Korumalıdır çünkü varsayılan uygulama, kurucuyu atlatarak tüm alanların (özel dahil) basit bir üye kopyası oluşturur . Bu, bir nesnenin ilk etapta işlemek üzere tasarlanabileceği bir şey değildir (örneğin, paylaşılan bir listede oluşturulan nesne örneklerini veya benzer bir şeyi izleyebilir).

Aynı nedenden ötürü, varsayılan uygulaması, clone()çağrıldığı nesne uygulanmazsa atar Cloneable. Bu, geniş kapsamlı sonuçları olan potansiyel olarak güvenli olmayan bir işlemdir ve bu nedenle sınıfın yazarının açıkça kabul etmesi gerekir.


Aslında varsayılan uygulama (nesnede) belgelere göre bir istisna atıyor ...
Bill K

2
Hayır, sadece fırlatmıyor. JavaDoc'undan: "Object sınıfı için klon yöntemi, belirli bir klonlama işlemi gerçekleştirir. İlk olarak, bu nesnenin sınıfı Cloneable arabirimini uygulamazsa, bir CloneNotSupportedException oluşturulur. Tüm dizilerin Cloneable arabirimini uyguladığı kabul edilir. Aksi takdirde, bu yöntem, bu nesnenin sınıfının yeni bir örneğini oluşturur ve tüm alanlarını, sanki atama yoluyla bu nesnenin karşılık gelen alanlarının içerikleriyle başlatır; alanların içeriği kendi başlarına klonlanmaz. "
Pavel Minaev

2

Cloneable'ın javadoc'undan.

* 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.

Böylece her nesnede klon çağırabilirsiniz, ancak bu size çoğu zaman istediğiniz sonuçları veya bir istisnayı vermez. Ancak, yalnızca klonlanabilir uygularsanız teşvik edilir.


2
Sen olamaz o korunmuş çünkü her Nesne üzerine klonu çağrı!
Pavel Minaev

2

IMHO bu kadar basit:

  • #clone klonlanamayan nesnelere çağrılmamalıdır, bu nedenle kamuya açıklanmaz
  • #cloneObjectDoğru sınıfın sığ kopyasını elde etmek için Cloneable'ı uygulayan ob alt sınıfları tarafından çağrılmalıdır

Alt sınıflar tarafından çağrılabilen, ancak diğer sınıflar tarafından çağrılamayan yöntemler için doğru kapsam nedir?

Bu protected.

CloneableElbette uygulayan sınıflar bu yöntemi herkese açık hale getirecek ve böylece diğer sınıflardan çağrılabilecektir.


0

Clone () yönteminde dahili olarak bir 'Cloneable örneğinin olup olmadığı' denetimi vardır. Bu, Java ekibinin clone () method.clone () yönteminin uygunsuz kullanımını kısıtlayacağını düşünebileceği şekilde korunur, yani yalnızca alt sınıflar tarafından erişilebilir. Object, tüm alt sınıfların ebeveyn sınıfı olduğundan, Clone () yöntemi, yukarıdaki 'Cloneable örneği' kontrolüne sahip değilsek, tüm sınıflar tarafından kullanılabilir. Java ekibinin, clone () yönteminde 'Cloneable örneğidir' kontrolünü yaptırarak clone () 'un uygunsuz kullanımını kısıtlamayı düşünmesinin nedeni budur.

Bu nedenle, cloneable uygulayan sınıflar, Object sınıfının clone () yöntemini kullanabilir.

Ayrıca korumalı hale getirdiği için, yalnızca klonlanabilir arabirimi uygulayan alt sınıflar tarafından kullanılabilir. Herkese açık hale getirmek istiyorsak, bu yöntemin alt sınıf tarafından kendi uygulamaları ile geçersiz kılınması gerekir.


-2

Evet, karşılaştığım sorunla aynı. Ama bu kodu uygulayarak çözüyorum

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;
    }
}

Tıpkı birinin söylediği gibi.


1
CloneNotSupportedException, denetlenmemiş olması gereken kontrol edilmiş bir istisnanın başka bir örneğidir (yani, Exception'ı değil RuntimeException'ı genişletmelidir). Side sınıfındaki clone () yöntemi Cloneable'ı uygular ve bu nedenle CloneNotSupportedException'ı asla atmazsa da, Side.clone () yine de istisnayı yakalamalı veya bildirmelidir. Bu, clone () yöntemine gereksiz istisna işleme gürültüsü ekler.
Derek Mahar

-2

Güneş geliştiricileri de sadece insandır ve gerçekten de klon yöntemini korumalı olarak uygulamak için büyük bir hata yaptılar, ArrayList'te işlevsiz bir klon yöntemi uyguladıklarıyla aynı hata! Bu nedenle, genel olarak, deneyimli Java programcılarının bile klon yöntemi hakkında çok daha derin bir yanlış anlaşılması vardır.

Bununla birlikte, son zamanlarda herhangi bir nesneyi tüm içeriği ile kopyalamak için hızlı ve kolay bir çözüm buldum, nasıl oluşturulduğu ve ne içerdiğine bakılmaksızın, cevabıma buradan bakın: Object.clone () kullanımında hata


-3

Yine, Java JDK çerçevesi mükemmel bir düşünce sergiliyor:

Klonlanabilir arayüz bir "genel T klonu ()" içermez; yöntem çünkü bir örneğin klonlanmasına izin veren bir öznitelik (örn. Seri hale getirilebilir) gibi davranır.

Bu tasarımda yanlış bir şey yok çünkü:

  1. Object.clone (), özel tanımlı sınıfınızla istediğinizi yapmayacaktır.

  2. Myclass varsa Cloneable => "public MyClass clone ()" ile clone () üzerine yazarsınız

  3. MyInterface, Cloneable'ı genişletir ve MyInterface'i uygulayan bazı MyClasses'ınız varsa: "public MyInterface clone ()"; arabirimde ve MyInterface nesnelerini kullanan her yöntem, MyClass sınıfı ne olursa olsun onları klonlayabilecektir.


2
Sınıfınız miras alınırsa, türetilmiş sınıf klon uygulamanız, temel sınıf uygulamalarınız güvenli klon yöntemleri sağlayana kadar güvenli olmayacaktır. Ayrıca, yöntem / özellik olmadan bir arayüze sahip olmak alışılmadık bir tasarım koşuludur. Bu arabirim, sınıfı klon uygulamaya zorlamaz.
prap19
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.