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


112

Qual è il motivo specifico che clone()viene definito protetto in java.lang.Object?

Risposte:


107

Il fatto che il clone sia protetto è estremamente dubbio, così come il fatto che il clonemetodo non sia dichiarato Cloneablenell'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 Cloneablema 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 "


2
Se l'oggetto non è clonabile, clone () di Object genererà CloneNotSupportedException. Quindi è necessario essere clonabili se si chiama super.clone () (con conseguente chiamata di Object.clone ()). Non vedo come un oggetto possa essere serializzato senza implementare Serializable.
Steve Kuo

1
"Penso che il design di Cloneable sia ora ampiamente considerato un errore." [citazione necessaria]
Kevin Panko

Scusa, non lo stavo insinuando. Stavo semplicemente che implica che "buono" il design è quello di non fare un'interfaccia estendere 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!
oxbow_lakes

6
@Kevin - L' efficace Java pp45 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"
oxbow_lakes

Anche sulla stessa pagina: "Questo è un uso molto atipico di interfacce e non uno da emulare" e "Affinché implementando l'interfaccia avere alcun effetto su una classe, e tutte le sue superclassi deve obbedire un piuttosto complesso, protocollo inapplicabile e in gran parte non documentato "
oxbow_lakes

30

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.)


Il che va bene, fino a quando non inserisci le interfacce nel mix - prova a clonare un'implementazione sconosciuta diSet
oxbow_lakes

@oxbow_lakes: ma forse alcune implementazioni di Set non sono clonabili
newacct

3
Non puoi clonare nulla che non implementa l'interfaccia Clonable - è un indicatore che dice "Questa classe è correttamente clonabile" - molto simile all'interfaccia Serializable. A proposito, c'è un modo per clonare le classi tramite serializzazione che funziona bene - google qualcosa come "clone di serializzazione java" e probabilmente troverai una manciata di modi per ottenere una copia completa del tuo oggetto.
Bill K

4
Non puoi clonare nulla che non implementa l'interfaccia Clonabile, ma solo perché qualcosa implementa l'interfaccia Clonabile non significa che puoi clonarla.
Michael Myers

1
@BuckCherry toString ha un'implementazione predefinita, se lo chiami succederà qualcosa di buono e riceverai una stringa. equals ha un'implementazione predefinita (uguale a ==). Il clone non può avere un'implementazione predefinita. Se chiami clone su un oggetto che non lo ha implementato, non otterrai un comportamento ragionevole. La clonazione è complicata e non può essere eseguita automaticamente (alcuni oggetti senza costruttori predefiniti possono essere impossibili da clonare genericamente), quindi per impostazione predefinita lo rendono un po 'più sicuro. Penso che metterlo su Object, tuttavia, potrebbe non essere stato necessario.
Bill K

7

cloneè protetto perché è qualcosa che dovrebbe essere sovrascritto in modo che sia specifico per la classe corrente. Anche se sarebbe possibile creare un clonemetodo pubblico che clonerebbe qualsiasi oggetto, ciò non sarebbe buono come un metodo scritto specificamente per la classe che ne ha bisogno.


ma perché deve essere protetto per questo?
Janusz

3
È protetto, quindi non usi quello nell'oggetto (in ogni caso genererà un'eccezione). Vogliono che tu lo sovrascriva in una classe, quindi lo rendi pubblico. (ha risposto anche un paio di volte sotto)
Bill K

1
E inutile se si considerano le interfacce come da mio punto di seguito
oxbow_lakes il

dovrebbe essere sovrascritto non è molto chiaro quindi avrebbe dovuto essere astratto e quindi non deve in Object Class, sto cercando di capire perché è così.
Kumar Abhishek

4

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.


2

È 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.


In realtà l'implementazione predefinita (in oggetto) genera un'eccezione secondo i documenti ...
Bill K

2
No, non si limita a lanciare. Dal suo JavaDoc: "Il metodo clone per la classe Object esegue un'operazione di clonazione specifica. Innanzitutto, se la classe di questo oggetto non implementa l'interfaccia Cloneable, viene generata un'eccezione CloneNotSupportedException. Si noti che tutti gli array sono considerati implementare l'interfaccia Cloneable. Altrimenti, questo metodo crea una nuova istanza della classe di questo oggetto e inizializza tutti i suoi campi con esattamente il contenuto dei campi corrispondenti di questo oggetto, come per assegnazione; i contenuti dei campi non vengono clonati. "
Pavel Minaev

2

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.


2
Non puoi chiamare clone su ogni oggetto, perché è protetto!
Pavel Minaev

2

IMHO è così semplice:

  • #clone non deve essere richiamato su oggetti non clonabili, pertanto non è reso pubblico
  • #clonedeve essere chiamato dalle sottoclassi ob Objectche implementano Cloneable per ottenere la copia superficiale della classe corretta

Qual è il giusto ambito per i metodi che devono essere richiamabili da sottoclassi, ma non da altre classi?

È protected.

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


0

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.


-2

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.


1
CloneNotSupportedException è un altro esempio di un'eccezione selezionata che dovrebbe essere deselezionata (ovvero, dovrebbe estendere RuntimeException, non Exception). Sebbene il metodo clone () nella classe Side implementi Cloneable e quindi non genererà mai CloneNotSupportedException, Side.clone () deve comunque catturare o dichiarare l'eccezione. Questo aggiunge solo rumore superfluo per la gestione delle eccezioni al metodo clone ().
Derek Mahar

-2

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 ()


-3

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é:

  1. Object.clone () non farà quello che vuoi con la tua classe definita dall'utente.

  2. Se hai Myclass implements Cloneable => sovrascrivi clone () con "public MyClass clone ()"

  3. 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.


2
se la tua classe viene ereditata, l'implementazione del clone della classe derivata non sarà sicura fino a quando le implementazioni della classe base non forniranno metodi di clonazione sicuri. Inoltre, è una specie di condizione di progettazione insolita avere un'interfaccia senza metodo / attributo. Questa interfaccia non forza la classe a implementare il clone.
prap19
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.