Domanda

Stavo cercando alcuni tutorial che spiegassero Java Cloneable, ma non ho ottenuto alcun buon collegamento e Stack Overflow sta comunque diventando una scelta più ovvia.

Vorrei sapere quanto segue:

  1. Cloneable significa che possiamo avere un clone o una copia di oggetti, implementando il Cloneable interfaccia.Quali sono i vantaggi e gli svantaggi di farlo?
  2. In che modo si verifica la clonazione ricorsiva se l'oggetto è un oggetto composito?
È stato utile?

Soluzione

La prima cosa che dovete sapere su Cloneable è -. Non ne fanno uso

E 'molto difficile da attuare la clonazione con Cloneable a destra, e lo sforzo non vale la pena.

Al posto di tale uso alcune altre opzioni, come Apache-commons SerializationUtils (deep-clone) o BeanUtils (shallow clone), o semplicemente utilizzare un costruttore di copia.

Vedi qui per le opinioni di Josh Bloch sulla clonazione con Cloneable, il che spiega il molti inconvenienti dell'approccio. ( Joshua Bloch era un impiegato di Sun, e ha portato allo sviluppo di numerose caratteristiche di Java.)

Altri suggerimenti

Sfortunatamente Cloneable è solo un'interfaccia marcatore, cioè:non definisce il metodo clone().

Ciò che fa è modificare il comportamento del metodo protetto Object.clone(), che lancerà un'eccezione CloneNotSupportedException per le classi che non implementano Cloneable ed eseguirà una copia superficiale a livello di membro per le classi che lo fanno.

Anche se questo è il comportamento che stai cercando, dovrai comunque implementare il tuo metodo clone() per renderlo pubblico.

Quando implementi il ​​tuo clone(), l'idea è di iniziare con l'oggetto creato da super.clone(), che è garantito essere della classe corretta, e quindi eseguire qualsiasi ulteriore popolamento di campi nel caso in cui una copia superficiale non sia ciò che serve tu vuoi.Chiamare un costruttore da clone() sarebbe problematico poiché ciò interromperebbe l'ereditarietà nel caso in cui una sottoclasse voglia aggiungere la propria logica clonabile aggiuntiva;se dovesse chiamare super.clone() otterrebbe un oggetto della classe sbagliata in questo caso.

Questo approccio tuttavia ignora qualsiasi logica che potrebbe essere definita nei costruttori, il che potrebbe essere potenzialmente problematico.

Un altro problema è che qualsiasi sottoclasse che dimentica di sovrascrivere clone() erediterà automaticamente la copia superficiale predefinita, che probabilmente non è ciò che desideri in caso di stato mutabile (che ora sarà condiviso tra il sorgente e la copia).

La maggior parte degli sviluppatori non utilizza Cloneable per questi motivi e implementa semplicemente un costruttore di copie.

Per ulteriori informazioni e le potenziali insidie ​​​​di Cloneable, consiglio vivamente il libro Effective Java di Joshua Bloch

  1. La clonazione invoca un modo extra-linguistica della costruzione di oggetti - senza costruttori.
  2. La clonazione richiede di trattare in qualche modo con CloneNotSupportedException -. O di preoccuparsi codice client per il trattamento di esso
  3. I vantaggi sono piccole - semplicemente non è necessario scrivere manualmente un costruttore copiare
  4. .

Quindi, utilizzare Cloneable con giudizio. Esso non ti dà benefici sufficienti in confronto con lo sforzo è necessario applicare a fare tutto bene.

La clonazione è un paradigma di programmazione di base.Il fatto che Java possa averlo implementato male in molti modi non diminuisce affatto la necessità della clonazione.Ed è facile implementare la clonazione che funzionerà nel modo in cui desideri che funzioni: superficiale, profonda, mista, qualunque cosa.Puoi anche utilizzare il nome clone per la funzione e non implementare Cloneable, se lo desideri.

Supponiamo di avere le classi A, B e C, dove B e C derivano da A.Se ho un elenco di oggetti di tipo A come questo:

ArrayList<A> list1;

Ora, quell'elenco può contenere oggetti di tipo A, B o C.Non sai di che tipo sono gli oggetti.Quindi, non puoi copiare l'elenco in questo modo:

ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
    list2.add(new A(a));
}

Se l'oggetto è effettivamente di tipo B o C, non otterrai la copia corretta.E se A fosse astratto?Ora, alcune persone hanno suggerito questo:

ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
    if(a instanceof A) {
        list2.add(new A(a));
    } else if(a instanceof B) {
        list2.add(new B(a));
    } else if(a instanceof C) {
        list2.add(new C(a));
    }
}

Questa è una pessima idea.Cosa succede se aggiungi un nuovo tipo derivato?Cosa succede se B o C si trovano in un altro pacchetto e non hai accesso ad essi in questa classe?

Quello che vorresti fare è questo:

ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
    list2.add(a.clone());
}

Molte persone hanno indicato perché l'implementazione Java di base di clone è problematica.Ma è facilmente superabile in questo modo:

Nella classe A:

public A clone() {
    return new A(this);
}

Nella classe B:

@Override
public B clone() {
    return new B(this);
}

Nella classe C:

@Override
public C clone() {
    return new C(this):
}

Non sto implementando Cloneable, sto solo usando lo stesso nome di funzione.Se non ti piace, chiamalo qualcos'altro.

A) Non ci sono un sacco di vantaggi di clone di più di un costruttore di copia. Probabilmente il più grande è la capacità di creare un nuovo oggetto dello stesso identico tipo dinamico (assumendo che il tipo dichiarato è clonabile e ha un metodo clone pubblico).

B) Il clone di default di creare una copia, e rimarrà una copia a meno che il clone di implementazione cambia questo. Questo può essere difficile, soprattutto se la classe ha campi finali

Bozho è giusto, clone può essere difficile da ottenere. Un costruttore di copia / fabbrica servirà maggior parte delle esigenze.

Quali sono gli svantaggi di Cloneable?

La clonazione è molto pericoloso se l'oggetto che si sta copiando ha composition.You bisogno di pensare al di sotto di possibile effetto collaterale in questo caso perché clone crea copia superficiale:

Diciamo che avete un oggetto da maneggiare db manipolazione correlate. Dire, che ha oggetto oggetto Connection come una delle proprietà.

Così, quando qualcuno crea clone di originalObject, l'oggetto viene creato, diciamo, cloneObject. Qui il originalObject e cloneObject tenere la stessa riferimento per oggetto Connection.

diciamo originalObject chiude l'oggetto Connection, così ora il cloneObject non funzionerà perché l'oggetto connection stato ripartito tra loro ed è stato actaually chiusa dal originalObject.

problema simile può verificarsi se lasci dire che si desidera clonare un oggetto che ha iostream come una proprietà.

Come funziona la clonazione ricorsiva accadere se l'oggetto è un oggetto composto?

esegue Cloneable copia superficiale. Significato è che i dati di oggetto originale ed oggetto clone indicheranno stesso riferimento / memoria. al contrario, nel caso di copia completa, dati dalla memoria di oggetto originale viene copiato nella memoria dell'oggetto clone.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top