Perché Cloneable non è deprecato?


139

Resta inteso che l' Cloneableinterfaccia in Java è interrotta. Ci sono molte ragioni per questo, che non menzionerò; altri lo hanno già fatto. È anche la posizione degli stessi architetti Java .

La mia domanda è quindi: perché non è ancora stato deprecato? Se il nucleo del team Java ha deciso che si è rotto, allora deve anche aver considerato la deprecazione. Quali sono i loro motivi per non farlo (in Java 8 non è ancora deprecato )?


41
Questa domanda non è "principalmente basata sull'opinione", come apparentemente molti sembrano sentirsi in diritto di giudicare. Coloro che non hanno altro che un'opinione sui motivi semplicemente non sono qualificati per rispondere. Tuttavia, è vero che hai solo una remota possibilità di ottenere una risposta autorevole qui. È anche vero che la tua domanda non riguarda un problema risolvibile che hai, quindi è almeno borderline off-topic.
Marko Topolnik,

6
@MarkoTopolnik Sono d'accordo che ci sono alcune persone là fuori al mondo che potrebbero fornire una risposta autorevole, ma non credo che sia il test che applichiamo qui. Il motivo di chiusura afferma che "le risposte a questa domanda tenderanno ad essere quasi interamente basate su opinioni". Sospetto che sarà così, a meno che non siamo molto fortunati.
Duncan Jones,

2
Ecco "Come e quando" deprezzarsi da Oracle ... ( docs.oracle.com/javase/6/docs/technotes/guides/javadoc/… ) L'interfaccia clonabile potrebbe rientrare nel caso "buggy, o altamente inefficiente" ma è molto aperto alle opinioni.
Maxx,

8
@Duncan Non ritengo ancora giusto esprimere un giudizio sulla domanda in base alle mie ipotesi sulla mancanza di disciplina da parte dei rispondenti . Se un utente non conosce il motivo per cui gli viene chiesto, non ha il diritto di abusare della struttura di risposta per presentare la propria opinione in merito.
Marko Topolnik,

4
@lexicore Sì, esattamente --- e puoi scommettere che hanno considerato a fondo quell'opzione e, di conseguenza, devono avere forti ragioni per non deprecarla. Le loro stesse critiche Cloneablesono ampiamente note.
Marko Topolnik,

Risposte:


120

Nel 1997 è stato inviato un bug al database dei bug Java sull'aggiunta del clone()metodo Cloneable, quindi non sarebbe più inutile. È stato chiuso con la risoluzione "non risolto" e la giustificazione era la seguente:

Il Comitato di revisione tecnica (TRC) di Sun ha esaminato a fondo questo problema e ha raccomandato di non intraprendere alcuna azione diversa dal miglioramento della documentazione dell'attuale interfaccia Cloneable . Ecco il testo completo della raccomandazione:

Le API di clonazione di oggetti Java esistenti sono problematiche. Esiste un metodo "clone" protetto su java.lang.Object e c'è un'interfaccia java.lang.Cloneable. L'intenzione è che se una classe vuole consentire ad altre persone di clonarla, dovrebbe supportare l'interfaccia Cloneable e sovrascrivere il metodo clone protetto predefinito con un metodo clone pubblico. Sfortunatamente, per ragioni convenientemente perse nella notte dei tempi, l'interfaccia Cloneable non definisce un metodo clone.

Questa combinazione si traduce in una discreta confusione. Alcune classi affermano di supportare Cloneable, ma dimenticano accidentalmente di supportare il metodo clone. Gli sviluppatori sono confusi su come dovrebbe funzionare Cloneable e su cosa dovrebbe fare il clone.

Sfortunatamente, l'aggiunta di un metodo "clone" a Cloneable sarebbe una modifica incompatibile. Non romperà la compatibilità binaria, ma romperà la compatibilità dei sorgenti. Prove aneddotiche suggeriscono che in pratica ci sono un certo numero di casi in cui le classi supportano l'interfaccia Cloneable ma non forniscono un metodo di clonazione pubblica. Dopo la discussione, TRC ha raccomandato all'unanimità di NON modificare l'interfaccia Cloneable esistente, a causa dell'impatto sulla compatibilità.

Una proposta alternativa era quella di aggiungere una nuova interfaccia java.lang.PubliclyCloneable per riflettere lo scopo originale previsto di Cloneable. A maggioranza di 5 o 2, TRC ha raccomandato di non farlo. La preoccupazione principale era che ciò avrebbe aggiunto ulteriore confusione (inclusa la confusione ortografica!) A un'immagine già confusa.

TRC ha raccomandato all'unanimità di aggiungere ulteriore documentazione all'interfaccia Cloneable esistente per descrivere meglio come deve essere utilizzata e per descrivere le "migliori pratiche" per gli implementatori.

Quindi, sebbene non si tratti direttamente di deprecato , la ragione per non rendere Cloneable "deprecato" è che il comitato di revisione tecnica ha deciso che la modifica della documentazione esistente sarà sufficiente per rendere utile questa interfaccia. E così fecero. Fino a Java 1.4, è Cloneablestato documentato come segue:

Una classe implementa l'interfaccia Cloneable per indicare al metodo Object.clone () che è legale per quel metodo fare una copia campo per campo delle istanze di quella classe.

I tentativi di clonare istanze che non implementano l'interfaccia Cloneable danno come risultato l'eccezione CloneNotSupportedException.

L'interfaccia Cloneable non dichiara metodi.

Da Java 1.4 (che è stato rilasciato nel febbraio 2002) fino all'edizione corrente (Java 8) è simile al seguente:

Una classe implementa l'interfaccia Cloneable per indicare al metodo Object.clone () che è legale per quel metodo fare una copia campo per campo delle istanze di quella classe. Se si richiama il metodo clone di Object su un'istanza che non implementa l'interfaccia Cloneable, viene generata l'eccezione CloneNotSupportedException.

Per convenzione, le classi che implementano questa interfaccia dovrebbero sovrascrivere Object.clone (che è protetto) con un metodo pubblico. Vedi Object.clone () per i dettagli sulla sostituzione di questo metodo.

Si noti che questa interfaccia non contiene il metodo clone. Pertanto, non è possibile clonare un oggetto semplicemente in virtù del fatto che implementa questa interfaccia. Anche se il metodo clone viene invocato in modo riflessivo, non vi è alcuna garanzia che abbia successo.


3
e sai perché il clonemetodo era in Objectprimo luogo?
njzk2,

8
@ njzk2 Questa è una parte essenziale del meccanismo --- è il metodo che fa la magia extralinguistica di basso livello nel copiare l'immagine dell'oggetto bit per bit.
Marko Topolnik,

3
@Unheilig Quella magia è qualcosa che non puoi replicare con un costruttore di copie: Object#clone()produce un'istanza della stessa classe dell'originale senza che quella classe sia nota al momento della compilazione.
Marko Topolnik,

4
@AVolpe: Ciò non risolveva l'incompatibilità di origine menzionata nella risposta "dove le classi supportano l'interfaccia Cloneable ma non riescono a fornire un metodo di clonazione pubblico". In particolare, le classi che forniscono un metodo di clone non pubblico verrebbero interrotte.
Louis Wasserman,

2
Bella storia. Ecco un link diretto al database dei bug. Ho aggiunto un po 'più di storia lì e ne ho citato parti nella mia risposta .
Stuart Marks

64

La risposta breve a "perché non è Cloneabledeprecato?" (o, in effetti, perché non è Xdeprecato, per nessuno X) è che non è stata prestata molta attenzione a deprecarli.

La maggior parte delle cose che sono state deprecate di recente sono state deprecate perché esiste un piano specifico per rimuoverle. Ad esempio, i metodi addPropertyChangeListenere removePropertyChangeListenerdi LogManager sono stati deprecati in Java SE 8 con l'intenzione di rimuoverli in Java SE 9. (Il motivo è che hanno inutilmente complicate interdipendenze tra i moduli.) In effetti, queste API sono già state rimosse dallo sviluppo iniziale di JDK 9 costruisce. (Notare che sono state rimosse anche chiamate di listener di modifica proprietà simili Pack200; vedere JDK-8029806 .)

Nessun piano simile esiste per Cloneablee Object.clone().

Una risposta più lunga implicherebbe la discussione di ulteriori domande, come ad esempio cosa ci si potrebbe aspettare da queste API, quali costi o benefici maturerebbero sulla piattaforma se fossero deprecati e cosa viene comunicato agli sviluppatori quando un'API è deprecata. Ho esplorato questo argomento nel mio recente discorso su JavaOne, Debito e deprecazione . (Diapositive disponibili su quel link; video qui .) Si scopre che il JDK stesso non è stato molto coerente nel suo uso della deprecazione. È stato usato per significare diverse cose, tra cui ad esempio

  • Questo è pericoloso e si dovrebbe essere consapevoli dei rischi di utilizzo (ad esempio: Thread.stop(), Thread.resume(), e Thread.suspend()).

  • Questo verrà rimosso in una versione futura

  • Questo è obsoleto ed è una buona idea usare qualcosa di diverso (esempio: molti dei metodi in java.util.Date)

Tutti questi sono significati distinti e diversi sottoinsiemi si applicano a cose diverse che sono deprecate. E alcuni sottoinsiemi si applicano a cose che non sono deprecate (ma che forse dovrebbero essere deprecate).

Cloneablee Object.clone()sono "rotti" nel senso che hanno difetti di progettazione e sono difficili da usare correttamente. Tuttavia, clone()è ancora il modo migliore per copiare le matrici e la clonazione ha un'utilità limitata per creare copie di istanze di classi che vengono implementate con cura. Rimuovere la clonazione sarebbe un cambiamento incompatibile che spezzerebbe molte cose. Un'operazione di clonazione potrebbe essere reimplementata in un modo diverso, ma probabilmente sarebbe più lenta di Object.clone().

Tuttavia, per la maggior parte delle cose un costruttore di copie è preferibile alla clonazione. Quindi, forse contrassegnare Cloneablecome "obsoleto" o "sostituito" o qualcosa di simile sarebbe appropriato. Questo direbbe agli sviluppatori che probabilmente vogliono cercare altrove, ma non segnalerebbe che il meccanismo di clonazione potrebbe essere rimosso in una versione futura. Sfortunatamente, non esiste un marcatore simile.

Allo stato attuale, la "deprecazione" sembra implicare un'eventuale rimozione - nonostante il fatto che un numero incredibilmente piccolo di funzioni deprecate sia mai stato rimosso - e quindi la deprecazione non sembra giustificata per il meccanismo di clonazione. Forse in futuro può essere applicato un marchio alternativo che indichi agli sviluppatori di utilizzare invece meccanismi alternativi.

AGGIORNARE

Ho aggiunto un po 'di cronologia aggiuntiva alla segnalazione di bug . Frank Yellin, uno dei primi implementatori di JVM e coautore della specifica JVM, ha fatto alcuni commenti in risposta al commento "perso nella notte dei tempi" nella raccomandazione TRC citata nell'altra risposta . Ho citato le parti pertinenti qui; il messaggio completo è nella segnalazione di bug.

Cloneable non ha metodi per lo stesso motivo di Serializable. Clonabile indica una proprietà della classe, piuttosto che dire specificamente qualcosa sui metodi supportati dalla classe.

Prima della riflessione, avevamo bisogno di un metodo nativo per creare una copia superficiale di un oggetto. Quindi è nato Object.clone (). Era anche chiaro che molte classi avrebbero voluto sovrascrivere questo metodo e che non tutte le classi avrebbero voluto essere clonate. Quindi Cloneable è nato per indicare l'intenzione del programmatore.

Quindi, in breve. Lo scopo di Cloneable non era quello di indicare che avevi un metodo clone () pubblico. Indicava che eri disposto a essere clonato usando Object.clone () e dipendeva dall'implementazione decidere se rendere pubblico clone ().


3
Una bella risposta che hai qui signore. In particolare, mi piace il fatto che non si getti Object.clone()nel fuoco solo perché tutti gli altri lo vogliono, ma si è disposti a ragionare e tirar fuori le cose buone.
Icza,

2
Tuttavia, clone () è ancora il modo migliore per copiare le matrici e la clonazione ha una utilità limitata per fare copie di istanze di classi che sono implementate con cura. Ero sotto l'impressione con la correzione di 6428387, tutti i percorsi del codice (clone, new / arrayCopy, Arrays.copyOf) hanno prodotto gli stessi valori intrinseci. Qualcosa è cambiato di recente?
bestsss

2
@bestsss Non credo array.clone()sia necessariamente più veloce di qualsiasi alternativa. Dal punto di vista API è il modo più conciso per duplicare un array. Arrays.copyOf(array, newlen)si avvicina, ma richiede un parametro di lunghezza, che è ridondante se non si modifica la lunghezza.
Stuart segna il

2
@Holger Sì, per quanto possiamo vedere, questa è la prima effettiva rimozione di un'API dall'1.1. Nota anche che anche se siamo d'accordo che Thread.suspend()e Thread.stop()(no-arg) sono pericolosi, probabilmente non verranno rimossi - o modificati per generare un'eccezione incondizionatamente - perché le persone li usano davvero! Presumibilmente sono disposti a sopportare il rischio. Uno dei fattori attenuanti con gli ascoltatori di cambio di proprietà è che sono stati usati molto raramente, quindi l'impatto della loro rimozione è piccolo.
Stuart segna il

2
@Holger Concettualmente java.beanspotrebbe essere reso indipendente java.desktopdal momento che i bean sono solo un'API della libreria per le proprietà. Sfortunatamente se si scava nell'API dei bean ci sono molte dipendenze da AWT. L'implementazione ha ancora di più. Certamente potrebbe essere possibile districarli, ma farlo sembra molto più lavoro di, diciamo, districare la registrazione dai bean. L'intero sforzo di modularizzazione consiste nel fare questo districare; senza dubbio si potrebbe fare di più, ma poi Jigsaw impiegherebbe ancora più tempo.
Stuart Marks

-1

perché non è ancora deprecato?

Perché il JCP non ha ritenuto opportuno farlo e potrebbe non farlo mai. Chiediglielo. Stai chiedendo nel posto sbagliato.

Quali sono i motivi alla base del mantenimento di questa cosa nell'API Java

Nessuno rimuoverà mai nulla dall'API Java, a causa del requisito di compatibilità con le versioni precedenti. L'ultima volta che è successo è stato il cambiamento nel modello di eventi AWT tra 1.0 e 1.1 nel 1996/7.


17
Lo hanno rimosso (efficacemente) Thread.stop(Throwable)cambiando il suo contratto per lanciare sempre UnsupportedOperationExceptional chiamante (non al thread di destinazione!).
Marko Topolnik,

22
Cosa è successo nello stesso periodo? La rimozione della Thread.stop(Throwable)funzionalità è avvenuta in Java 8. In ogni caso, il consiglio non qualificato di "chiederglielo" è sbagliato perché oggi lo stesso architetto Java principale è un membro attivo di Stack Overflow. Semplicemente non si dà la briga di rispondere a nient'altro che alle domande relative agli stream.
Marko Topolnik,

13
Inoltre, la domanda di OP non riguarda la rimozione , ma la deprecazione e chiaramente la deprecazione si è verificata da sempre.
Marko Topolnik,

17
@EJP Non sto chiedendo se Cloneableverrà rimosso dall'API Java. Sto chiedendo perché non sarà depresso. E penso che questo sia un posto perfetto per chiedere.
Kao,

5
@VaheHarutyunyan Grazie per l'urlo, ma non sono un architetto di Java. Sono un ingegnere nel gruppo JDK di Oracle, che mantiene questa roba.
Stuart Marks
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.