Perché il metodo clone () è protetto in java.lang.Object?

Qual è la ragione specifica per cui clone() è definito come protetto in java.lang.Object ?

Il fatto che il clone sia protetto è estremamente dubbio – così come il fatto che il metodo clone non è dichiarato nell’interfaccia Cloneable .

Rende il metodo abbastanza inutile per prendere copie di dati perché non si può dire :

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

Penso che il design di Cloneable sia ora considerato in gran parte un errore (citazione sotto). Normalmente vorrei essere in grado di realizzare implementazioni di un’interfaccia Cloneable ma non necessariamente rendere l’interfaccia Cloneable (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 Josh Bloch’s Effective Java :
“L’interfaccia Cloneable era intesa come interfaccia di mixin per gli oggetti per pubblicizzare che consentono la clonazione, ma purtroppo non serve a questo scopo … Questo è un uso altamente atipico delle interfacce e non uno da emulare … Per implementare l’interfaccia per avere qualche effetto su una class, essa e tutte le sue superclassi devono obbedire a un protocollo abbastanza complesso, inapplicabile e in gran parte non documentato

L’interfaccia Clonable è solo un indicatore che dice che la class può supportare il clone. Il metodo è protetto perché non dovresti chiamarlo su object, puoi (e dovresti) sovrascriverlo come pubblico.

Dal sole:

Nella class Object, il metodo clone () è dichiarato protetto. Se tutto ciò che fai è implementare Cloneable, solo le sottoclassi ei membri dello stesso pacchetto saranno in grado di invocare clone () sull’object. Per abilitare qualsiasi class in qualsiasi pacchetto ad accedere al metodo clone (), dovrai sovrascriverlo e dichiararlo pubblico, come si fa di seguito. (Quando si esegue l’override di un metodo, è ansible renderlo meno privato, ma non più privato. Qui, il metodo clone () protetto in Object viene sovrascritto come metodo pubblico.)

clone è protetto perché è qualcosa che dovrebbe essere sovrascritto in modo che sia specifico per la class corrente. Mentre sarebbe ansible creare un metodo clone pubblico che clonasse qualsiasi object, questo non sarebbe valido come un metodo scritto specificamente per la class che ne ha bisogno.

Il metodo Clone non può essere utilizzato direttamente su alcun object, motivo per cui è destinato a essere sostituito dalla sottoclass.

Ovviamente potrebbe essere pubblico e lanciare un’eccezione appropriata quando la clonazione non è ansible, ma penso che sarebbe fuorviante.

Il modo in cui viene implementato il clone adesso ti fa riflettere sul perché vuoi usare il clone e su come vuoi che il tuo object sia clonato.

È protetto perché l’implementazione predefinita esegue una copia poco profonda di tutti i campi (incluso privato), costruttore elusivo. Questo non è qualcosa che un object potrebbe essere progettato per gestire in primo luogo (ad esempio, potrebbe tenere traccia delle istanze dell’object create in un elenco condiviso o qualcosa di simile).

Per lo stesso motivo, l’implementazione predefinita di clone() verrà lanciata se l’object su cui è chiamato non implementa Cloneable . È un’operazione potenzialmente pericolosa con conseguenze di vasta portata e pertanto l’autore della class deve esplicitamente opt-in.

Dal javadoc di cloneable.

 * By convention, classs that implement this interface (cloneable) should override * Object.clone (which is protected) with a public method. * See {@link java.lang.Object#clone()} for details on overriding this * method. * Note that this interface does not contain the clone 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 puoi chiamare clone su ogni object ma questo ti darebbe il più delle volte non i risultati che vuoi o un’eccezione. Ma è solo incoraggiato se si implementa Cloneable.

IMHO è semplice come questo:

  • #clone non deve essere chiamato su oggetti non clonabili, quindi non è reso pubblico
  • #clone deve essere chiamato da sottoclassi ob Object che implementa Cloneable per ottenere la copia superficiale della class giusta

Qual è lo spazio giusto per i metodi che possono essere richiamati dalle sottoclassi, ma non da altre classi?

È protected

Le classi che implementano Cloneable renderanno questo metodo pubblico in modo che possa essere chiamato da altre classi.

Il metodo Clone () ha un controllo internamente “istanza di Clonabile o non”. Questo è il modo in cui il team Java potrebbe limitare l’uso improprio del metodo clone (). Metodo.clone () è protetto, cioè accessibile solo da sottoclassi. Poiché l’object è la class genitore di tutte le sottoclassi, quindi il metodo Clone () può essere utilizzato da tutte le classi, se non si dispone di un controllo superiore di “istanza di Cloneable”. Questo è il motivo per cui il team Java potrebbe aver pensato di limitare l’uso improprio di clone () avendo il controllo nel metodo clone () ‘is it instance of Cloneable’.

Quindi, indipendentemente dalle classi che implementano cloneable, è ansible utilizzare il metodo clone () della class Object.

Inoltre, dal momento che è protetto, è disponibile solo per le sottoclassi che implementano l’interfaccia clonabile. Se vogliamo renderlo pubblico, questo metodo deve essere sovrascritto dalla sottoclass con la sua 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 prima che qualcuno dicesse.

Bene, anche gli sviluppatori di sole sono umani, e hanno fatto davvero un grosso errore nell’implementare il metodo clone come protetto, lo stesso errore con cui hanno implementato un metodo clone non funzionante in ArrayList! Quindi, in generale, esiste un malinteso molto più profondo anche dei programmatori Java esperti sul metodo clone.

Tuttavia, recentemente ho trovato una soluzione rapida e semplice per copiare qualsiasi object con tutto il suo contenuto, indipendentemente da come è stato creato e da ciò che contiene, vedere la mia risposta qui: Errore nell’uso di Object.clone ()

Ancora una volta, il framework JDK di Java mostra un pensiero brillante:

L’interfaccia Cloneable non contiene un “T clone pubblico ();” metodo perché agisce più come un attributo (ad esempio Serializable) che consente a un’istanza di essere clonata.

Non c’è nulla di sbagliato in questo design perché:

  1. Object.clone () non farà ciò che vuoi con la tua class personalizzata.

  2. Se hai Myclass implementa Cloneable => sovrascrivi clone () con “public MyClass clone ()”

  3. Se hai MyInterface estende Cloneable e alcune MyClasses implementando MyInterface: semplicemente definisci “public MyInterface clone ();” nell’interfaccia e ogni metodo che utilizza oggetti MyInterface sarà in grado di clonarli, indipendentemente dalla loro class MyClass.