Risposte:
Il fatto che il clone sia protetto è estremamente dubbio, così come il fatto che il clone
metodo non sia dichiarato Cloneable
nell'interfaccia.
Rende il metodo abbastanza inutile per prendere copie dei dati perché non puoi dire :
if(a instanceof Cloneable) {
copy = ((Cloneable) a).clone();
}
Penso che il design di Cloneable
è ora in gran parte considerato un errore (citazione sotto). Normalmente vorrei essere in grado di realizzare implementazioni di un'interfaccia Cloneable
ma non necessariamente rendere l'interfacciaCloneable
(simile all'uso di Serializable
). Questo non può essere fatto senza riflessione:
ISomething i = ...
if (i instanceof Cloneable) {
//DAMN! I Need to know about ISomethingImpl! Unless...
copy = (ISomething) i.getClass().getMethod("clone").invoke(i);
}
Citazione da Effective Java di Josh Bloch :
"L'interfaccia Cloneable era intesa come un'interfaccia mixin per gli oggetti per annunciare che consentono la clonazione. Sfortunatamente non serve a questo scopo ... Questo è un uso altamente atipico delle interfacce e non uno da emulare ... Affinché l'interfaccia abbia un effetto su una classe, essa e tutte le sue superclassi devono obbedire a un protocollo abbastanza complesso, inapplicabile e in gran parte non documentato "
Serializable
- è fino a implementazioni di decidere se implementare Serializable
. Lo stavo estendendo a Cloneable
- non è qualcosa che un'interfaccia dovrebbe estendere - ma un'implementazione di un'interfaccia è libera di essere Cloneable
. Il problema è che, se hai un parametro del tipo di interfaccia, gli chiedi se è clonabile; ma poi non puoi effettivamente clonarlo!
L'interfaccia clonabile è solo un indicatore che dice che la classe può supportare il clone. Il metodo è protetto perché non dovresti chiamarlo sull'oggetto, puoi (e dovresti) sovrascriverlo come pubblico.
Dal sole:
Nella classe Object, il metodo clone () è dichiarato protetto. Se tutto ciò che fai è implementare Cloneable, solo le sottoclassi e i membri dello stesso pacchetto saranno in grado di invocare clone () sull'oggetto. Per abilitare qualsiasi classe in qualsiasi pacchetto ad accedere al metodo clone (), dovrai sovrascriverlo e dichiararlo pubblico, come viene fatto di seguito. (Quando sovrascrivi un metodo, puoi renderlo meno privato, ma non più privato. Qui, il metodo protetto clone () in Object viene sovrascritto come metodo pubblico.)
Set
clone
è protetto perché è qualcosa che dovrebbe essere sovrascritto in modo che sia specifico per la classe corrente. Anche se sarebbe possibile creare un clone
metodo pubblico che clonerebbe qualsiasi oggetto, ciò non sarebbe buono come un metodo scritto specificamente per la classe che ne ha bisogno.
Il metodo Clone non può essere utilizzato direttamente su alcun oggetto, motivo per cui deve essere sovrascritto dalla sottoclasse.
Ovviamente potrebbe essere pubblico e lanciare un'eccezione appropriata quando la clonazione non è possibile, ma penso che sarebbe fuorviante.
Il modo in cui il clone viene implementato in questo momento ti fa pensare al motivo per cui desideri utilizzare il clone e al modo in cui desideri che il tuo oggetto venga clonato.
È protetto perché l'implementazione predefinita esegue una copia superficiale a livello di membro di tutti i campi (incluso privato), aggirando il costruttore . Questo non è qualcosa che un oggetto potrebbe essere progettato per gestire in primo luogo (ad esempio, potrebbe tenere traccia delle istanze di oggetti creati in un elenco condiviso o qualcosa di simile).
Per lo stesso motivo, l'implementazione predefinita di clone()
verrà generata se l'oggetto su cui viene chiamato non viene implementato Cloneable
. È un'operazione potenzialmente non sicura con conseguenze di vasta portata e pertanto l'autore della classe deve esplicitamente accettare.
Dal javadoc di cloneable.
* 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.
Quindi potresti chiamare clone su ogni oggetto, ma questo ti darebbe la maggior parte delle volte non i risultati desiderati o un'eccezione. Ma è incoraggiato solo se si implementa clonabile.
IMHO è così semplice:
#clone
non deve essere richiamato su oggetti non clonabili, pertanto non è reso pubblico#clone
deve essere chiamato dalle sottoclassi ob Object
che implementano Cloneable per ottenere la copia superficiale della classe correttaQual è il giusto ambito per i metodi che devono essere richiamabili da sottoclassi, ma non da altre classi?
È protected
.
Le classi che implementano Cloneable
ovviamente renderanno pubblico questo metodo in modo che possa essere chiamato da altre classi.
Il metodo Clone () ha un controllo interno 'istanza di Clonabile o no'. Questo è il modo in cui il team Java potrebbe pensare che limiterà l'uso improprio del metodo clone (). Il metodo clone () è protetto, cioè accessibile solo da sottoclassi. Poiché object è la classe genitore di tutte le sottoclassi, quindi il metodo Clone () può essere utilizzato da tutte le classi, infatti se non abbiamo il controllo precedente di 'instance of Cloneable'. Questo è il motivo per cui il team Java potrebbe aver pensato di limitare l'uso improprio di clone () facendo il segno di spunta nel metodo clone () "is it instance of Cloneable".
Quindi qualunque classe implementa cloneable può usare il metodo clone () della classe Object.
Inoltre, essendo protetto, è disponibile solo per quelle sottoclassi che implementano l'interfaccia clonabile. Se vogliamo renderlo pubblico, questo metodo deve essere sovrascritto dalla sottoclasse con la propria implementazione.
Sì, lo stesso problema che ho incontrato. Ma lo risolvo implementando questo codice
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;
}
}
Proprio come ha detto prima qualcuno.
Bene, anche gli sviluppatori del sole sono solo umani, e hanno fatto davvero un grosso errore nell'implementare il metodo clone come protetto, lo stesso errore in cui hanno implementato un metodo clone non funzionante in ArrayList! Quindi, in generale, esiste un malinteso molto più profondo anche di programmatori Java esperti sul metodo di clonazione.
Tuttavia, di recente ho trovato una soluzione semplice e veloce per copiare qualsiasi oggetto con tutto il suo contenuto, indipendentemente da come è costruito e da cosa contiene, vedi la mia risposta qui: Bug nell'uso di Object.clone ()
Ancora una volta, il framework Java JDK mostra un pensiero brillante:
L'interfaccia clonabile non contiene un "public T clone ();" perché agisce più come un attributo (es. Serializable) che consente di clonare un'istanza.
Non c'è niente di sbagliato in questo design perché:
Object.clone () non farà quello che vuoi con la tua classe definita dall'utente.
Se hai Myclass implements Cloneable => sovrascrivi clone () con "public MyClass clone ()"
Se hai MyInterface extends Cloneable e alcune MyClasses che implementano MyInterface: definisci semplicemente "public MyInterface clone ();" nell'interfaccia e ogni metodo che utilizza gli oggetti MyInterface sarà in grado di clonarli, indipendentemente dalla loro classe MyClass.