2013-04-03 18 views
6

Ho bisogno di dotare la mia classe con la clonazione polimorfica (copia completa), vale a dire ho bisogno di qualcosa di simile al lavoro:Il metodo Java clone() è l'unico modo per ottenere la clonazione polimorfica?

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

dove original.clone() può essere sostituito da qualsiasi meccanismo per creare una copia profonda, e il tipo effettivo di copy deve essere SubType, perché original è anche SubType.

Il metodo clone() e l'interfaccia Cloneable sono l'unico modo per ottenere questo risultato? Metodi di fabbrica e costruttori di copie non possono essere utilizzati, poiché la classe effettiva è nota solo in fase di esecuzione, giusto? Esistono altri metodi suggeriti, ad eccezione degli approcci serialize-deserialize, e lo Java deep-cloning library, che è IMHO ancora peggio della magia nera rispetto al metodo clone()?

Grazie, Petr

+0

Non è possibile creare un costruttore in cui si può passare l'oggetto che si desidera clonare? – Justin

+0

@gangqinlaohu Certo, posso, ma poi avrei bisogno di chiamare 'new SubType (original)' che non posso poiché non so al momento della scrittura del codice se l'originale è in realtà di classe 'SubType', o' SubType2' o 'SubSubType'. – Posa

risposta

4

Attualmente il metodo clone() dell'oggetto non consente di eseguire alcuna chiamata polimorfica poiché è protected. L'implementazione di Cloneable è inutile perché non contiene un metodo clone().

È possibile eseguire la clonazione polimorfica fornendo un metodo polimorfico per le classi clonate che a loro volta richiamano il costruttore di copie.

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 

Vedi anche:

Joshua Block's opinion on cloning vs. copy constructor

+0

OK, funzionerebbe. Ma in che senso questo è diverso dall'uso di 'clone()'? Il metodo 'deepCopy()' non ha un nome diverso? Le stesse cose che fai in 'deepCopy()' non possono essere fatte in 'clone()'? – Posa

+0

@Posa Cloning è un modo "incorporato" java per fornire copie di oggetti senza la necessità di un costruttore di copie. Ha cercato di semplificare la vita ai programmatori, ma IMO non è il caso. Sì, se hai molta cura quando esegui l'override di 'clone()' (l'Effectiva Java di Joshua Block ne ha un intero capitolo), dovresti ottenere gli stessi risultati. – dcernahoschi

1

è sufficiente aggiungere un metodo di copia per supertipo e implementare in tutti i sottotipi

class SuperType { 

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

Se non vi piace l'interfaccia Cloneable, è possibile creare la propria interfaccia. Ogni classe sarà responsabile della creazione di una nuova istanza del tipo corretto.

+0

Non si tratta del fatto che non mi piace 'Clonable'. Non capisco il panico di dont-use-clone (probabilmente non capisco l'emanazione relativa al 'clone' nonostante abbia letto il libro di J. Bloch). Perché dovrei ideare la mia interfaccia fondamentalmente per lo stesso scopo di 'Clonable'? O lo scopo della mia interfaccia sarebbe diverso da quello di "Clonabile"? – Posa

+0

Bene, la tua domanda era "Il metodo clone() e l'interfaccia Clonabile sono l'unico modo per ottenere questo?". Se il metodo clone() è ok per te, usalo. Tuttavia, l'utilizzo di un'interfaccia personalizzata ti consente di sfruttare i generici. – WilQu

2

Affinché il codice funzioni, che il codice è sia all'interno della classe SuperType o sottoclasse, o il tipo di SuperType deve avere un metodo pubblico clone(). Un metodo pubblico clone() non esiste automaticamente ed è necessario implementarlo. Potresti chiamarlo qualsiasi altra cosa, per esempio, ad es. copy().

La tua domanda, quindi, è come implementare il metodo clone() (o come lo chiami tu) in modo che faccia la clonazione polimorfica.

Il modo che è stato inteso dagli sviluppatori Java è chiamare super.clone(), assumendo che tutte le classi nella gerarchia di ereditarietà simile attuate clone() effettuare clonazione polimorfico. Questo alla fine arriva al metodo protetto Object.clone(), che fa la magia della clonazione polimorfica. Si noti che per Object.clone() non generare un'eccezione, la classe deve implementare l'interfaccia Cloneable.

Tuttavia, ci sono altri modi possibili. Ad esempio, supponendo che tutte le sottoclassi abbiano un costruttore predefinito, è possibile fare qualcosa come this.getClass().newInstance(). Questo creerà un oggetto della classe giusta, ma i campi non verranno copiati. Il tuo metodo clone dovrà copiare tutti i campi, e le sottoclassi devono sovrascrivere il metodo clone per copiare i loro campi, ecc. Si noti che è irrilevante se l'interfaccia Cloneable è implementata in questo caso.

Un altro modo è, supponendo che la classe sia serializzabile, serializzare e unserialize this. Questo dovrebbe creare un clone polimorfico con tutti i campi serializzabili riportati.