2013-04-03 9 views
6

Ich brauche meine Klasse mit polymorphen Klonen (tiefe Kopie) auszustatten, also brauche ich so etwas zu arbeiten:Ist die Java clone() -Methode der einzige Weg, polymorphes Klonen zu erreichen?

SuperType original = new SubType(); 
SuperType copy = original.clone(); 

wo original.clone() kann durch einen beliebigen Mechanismus ersetzt werden, um eine tiefe Kopie zu erstellen, und der tatsächliche Typ von copy soll SubType sein, denn original ist auch eine SubType.

Ist die clone() Methode und Cloneable Schnittstelle die einzige Möglichkeit, dies zu erreichen? Factory-Methoden und Kopierkonstruktoren können nicht verwendet werden, da die eigentliche Klasse nur zur Laufzeit bekannt ist, oder? Gibt es andere vorgeschlagene Methoden außer diese Serialisierung-Deserialisierung Ansätze, und die Java deep-cloning library, die IMHO ist noch schlimmer schwarze Magie als die clone() Methode?

Danke, Petr

+0

Sie können keinen Konstruktor erstellen, an den das Objekt, an das geklont werden soll, übergeben werden kann? – Justin

+0

@gangqinlaohu Sicher, ich kann, aber dann würde ich 'neue SubType (original)' nennen, was ich nicht kann, da ich nicht weiß, in der Zeit des Schreibens des Codes, wenn das Original tatsächlich der Klasse 'SubType' oder' SubType2' ist oder "SubSubType". – Posa

Antwort

4

Die Methode clone() des Objekts erlaubt Ihnen keine polymorphen Aufrufe, weil es protected ist. Die Implementierung Cloneable ist auch nicht sinnvoll, da sie keine clone()-Methode enthält.

Sie können polymorphes Klonen durchführen, indem Sie eine polymorphe Methode für die geklonten Klassen bereitstellen, die wiederum den Kopierkonstruktor aufrufen.

abstract class SuperType { 
    public SuperType(SuperType t) { 
    } 

    public abstract SuperType deepCopy(); 
} 

class SomeType extends SuperType { 

    SomeType(SomeType t) { 
     //copy constructor 
    } 

    @Override 
    public SomeType deepCopy() {       
     return new SomeType(this); 
    } 
} 

... 

SuperType original = new SubType(); 
SuperType copy = original.deepCopy(); //the deepCopy is called on children classes 

Siehe auch:

Joshua Block's opinion on cloning vs. copy constructor

+0

OK, das würde funktionieren. Aber in welchem ​​Sinne unterscheidet sich das von der Verwendung von 'clone()'? Ist die 'deepCopy()' Methode nicht einfach ein anderer Name? Können nicht die gleichen Dinge wie in 'deepCopy()' in 'clone()' gemacht werden? – Posa

+0

@Posa Cloning ist ein Java "eingebauter" Weg, um Objektkopien ohne den Bedarf eines Kopierkonstruktors bereitzustellen. Es hat versucht, den Programmierern das Leben zu erleichtern, aber IMO ist es nicht der Fall. Ja, wenn Sie beim Überschreiben von 'clone()' sehr vorsichtig sind (Joshua Block's Effectiva Java hat ein ganzes Kapitel darüber), sollten Sie die gleichen Ergebnisse erhalten. – dcernahoschi

1

Sie können einfach eine Kopiermethode zu übergeordneter Typ hinzufügen und implementieren sie in allen Subtypen

class SuperType { 

    public SuperType copy() { 
       ... 
    } 
} 
0

Wenn Sie die Cloneable Schnittstelle nicht mögen, können Sie Ihre eigene Schnittstelle erstellen können. Jede Klasse ist dafür verantwortlich, eine neue Instanz des richtigen Typs zu erstellen.

+0

Es geht nicht darum, dass ich 'Clonable' nicht mag. Ich verstehe nicht die dont-use-Klon Panik (wahrscheinlich verstehe ich nicht ganz das ausgegebene bezogen auf 'clone', obwohl ich J. Blochs Buch gelesen habe). Warum soll meine eigene Schnittstelle grundsätzlich für den gleichen Zweck wie "Clonable" entworfen werden? Oder würde sich der Zweck meiner eigenen Schnittstelle von dem von "Clonable" unterscheiden? – Posa

+0

Nun, Ihre Frage war "Ist die Klon() -Methode und Clonable-Schnittstelle der einzige Weg, dies zu erreichen?". Wenn die clone() -Methode für Sie in Ordnung ist, verwenden Sie sie. Mit einer benutzerdefinierten Schnittstelle können Sie jedoch Generika nutzen. – WilQu

2

Damit Ihr Code zu arbeiten, wird dieser Code entweder in der SuperType Klasse oder Unterklasse oder Ihren SuperType Typ eine öffentliche clone() Methode haben muss. Eine öffentliche clone()-Methode existiert nicht automatisch und Sie müssen sie implementieren. Du könntest es irgendetwas anderes für diese Angelegenheit nennen, z.B. copy().

Ihre Frage ist dann, wie Sie diese clone() (oder wie auch immer Sie es nennen) Methode implementieren, so dass es polymorphes Klonen macht.

Die von den Java-Entwicklern vorgesehene Methode lautet super.clone() unter der Annahme, dass alle Klassen in der Vererbungshierarchie clone() implementiert haben, um polymorphes Klonen durchzuführen. Dies gelangt schließlich zur geschützten Object.clone() Methode, die die Magie des polymorphen Klonens macht. Beachten Sie, dass für Object.clone(), um keine Ausnahme auszulösen, Ihre Klasse die Cloneable Schnittstelle implementieren muss.

Es gibt jedoch andere Möglichkeiten. Angenommen, dass alle Unterklassen einen Standardkonstruktor haben, können Sie beispielsweise this.getClass().newInstance() eingeben. Dadurch wird ein Objekt der richtigen Klasse erstellt, aber die Felder werden nicht kopiert. Ihre Klonmethode muss alle Felder kopieren, und Unterklassen müssen Ihre Klonmethode überschreiben, um ihre Felder usw. zu kopieren. Beachten Sie, dass es irrelevant ist, ob in diesem Fall die Schnittstelle Cloneable implementiert ist.

Eine andere Möglichkeit ist, unter der Annahme, dass die Klasse Serializable ist, zu serialisieren und unserialize this. Dies sollte einen polymorphen Klon erzeugen, der alle serialisierbaren Felder enthält.