Perché Java ha bisogno di un'interfaccia serializzabile?


114

Lavoriamo molto con la serializzazione e dover specificare un tag Serializable su ogni oggetto che utilizziamo è una specie di fardello. Soprattutto quando si tratta di una lezione di terze parti che non possiamo davvero cambiare.

La domanda è: poiché Serializable è un'interfaccia vuota e Java fornisce una solida serializzazione una volta aggiunta implements Serializable, perché non hanno reso tutto serializzabile e basta?

Cosa mi sto perdendo?


E se volessi rendere serializzabile il tuo oggetto? O ho frainteso qualcosa?
Joe Phillips,

Riceverò comunque NotSerializableException perché tutti i campi dei miei oggetti devono essere serializzabili
Yoni Roit

Completamente d'accordo con Pop Catalin e dmitry "Questo trucco serializzabile è solo un'altra decisione sbagliata che è stata presa una o due decine di anni fa". Non importa quanto possa essere pericolosa la serializzazione. E non è vero che dal momento che la dichiarazione è esplicita, allora "sai che devi prestare particolare attenzione": chiunque ne abbia bisogno prima mette le cose "implementa", e poi pensa all'implicazione se qualcosa è andato storto. Sarebbe stato tutto più chiaro se ci avessero fornito un'interfaccia "Non serializzabile" da applicare a casi speciali.
Jack

Risposte:


120

La serializzazione è piena di insidie. Il supporto della serializzazione automatica di questo modulo rende le parti interne della classe parte dell'API pubblica (motivo per cui javadoc fornisce le forme persistenti delle classi ).

Per la persistenza a lungo termine, la classe deve essere in grado di decodificare questo modulo, che limita le modifiche che è possibile apportare al design della classe. Questo rompe l'incapsulamento.

La serializzazione può anche portare a problemi di sicurezza. Essendo in grado di serializzare qualsiasi oggetto a cui ha un riferimento, una classe può accedere ai dati che normalmente non sarebbe in grado di (analizzando i dati byte risultanti).

Ci sono altri problemi, come la forma serializzata delle classi interne non ben definita.

Rendere serializzabili tutte le classi esacerberebbe questi problemi. Dai un'occhiata a Java Effective Second Edition , in particolare Item 74: Implement Serializable con giudizio .


2
Questa è chiaramente la risposta migliore, sono deluso dal fatto che la risposta selezionata non sia questa, sembra che il post abbia scelto con un'agenda "Sono infastidito perché devo dichiarare le cose serializzabili" in mente. È un esempio di qualcuno che vuole liberarsi e non prestare attenzione alle lezioni di sicurezza e design che sono già state apprese in passato.
gbtimmon

@ McDowell cosa intendi per forma persistente di classi? Ho seguito quel link ma non riesco a capire cosa intendi? puoi spiegare questo per favore?
Geek

@Geek - Il modulo serializzato del tipo di URL (ad esempio) definisce quali campi privati ​​deve avere il tipo e in quale ordine devono essere dichiarati.
McDowell

@ McDowell Perché l'ordine è importante?
Geek

12
@ McDowell Ciao. Sono il poster originale di questa domanda di 4 anni fa, e ho appena selezionato la tua risposta come accettata, se significa qualcosa. Penso che la tua risposta sia davvero la migliore, e probabilmente ero troppo immaturo per vederla in quel modo in quel momento. Correzione ora :)
Yoni Roit

32

Penso che entrambe le persone Java e .Net abbiano sbagliato questa volta, sarebbe stato meglio rendere tutto serializzabile per impostazione predefinita e invece è necessario contrassegnare solo quelle classi che non possono essere serializzate in modo sicuro.

Ad esempio in Smalltalk (un linguaggio creato negli anni '70) ogni oggetto è serializzabile per impostazione predefinita. Non ho idea del motivo per cui questo non sia il caso in Java, considerando il fatto che la stragrande maggioranza degli oggetti è sicura da serializzare e solo alcuni di essi non lo sono.

Contrassegnare un oggetto come serializzabile (con un'interfaccia) non rende magicamente quell'oggetto serializzabile, è stato sempre serializzabile , è solo che ora hai espresso qualcosa che il sistema avrebbe potuto trovare da solo, quindi non vedo una vera buona ragione per la serializzazione è così com'è ora.

Penso che sia stata una decisione sbagliata presa dai progettisti o la serializzazione fosse un ripensamento, o la piattaforma non era mai pronta per eseguire la serializzazione di default su tutti gli oggetti in modo sicuro e coerente.


26
È necessario prestare particolare attenzione durante la progettazione e l'implementazione di una classe per assicurarsi che le istanze vengano serializzate in modo ragionevole. L'interfaccia serializzabile in realtà significa: "Io, come programmatore, ho compreso le conseguenze della serializzazione e ho permesso alla JVM di serializzare questo"
Rolf Rander

@Rolf Rander: il più delle volte non è necessario prestare alcuna attenzione, basta contrassegnare la classe come serializzabile. Se la serializzazione fosse stata attivata per impostazione predefinita su tutti gli oggetti, anche la mentalità di ogni sviluppatore sarebbe stata diversa, sarebbe stato qualcosa di naturale da fare per rendere serializzabile una classe ...
Pop Catalin

avrebbe aggiunto un'altra preoccupazione all'elenco di un buon design di classe, come per esempio assicurarsi di non avere perdite di memoria. Tuttavia, un buon design di classe richiede sempre di più che le tue classi siano serializzabili quando possono esserlo.
Pop Catalin

3
@ StaxMan, perché rendersi conto in seguito che è necessario serializzare una classe e non è possibile, può essere molto costoso. È uno di quei casi in cui paga un piccolo sforzo in più. Ciò è particolarmente vero se stai scrivendo una libreria e qualcun altro la consumerà senza il codice sorgente
Pop Catalin

2
Sono completamente d'accordo con questa risposta. In molte lingue tutto è serializzabile per impostazione predefinita. E in realtà lo stesso con JVM, perché è facile usare Reflection per accedere a qualsiasi membro della classe, privato o meno. Questo Serializabletrucco è solo un'altra decisione sbagliata che è stata presa dieci o due anni fa, e un'ulteriore aggiunta al fastidio quando si ha a che fare con java puro, come alcuni difetti nella raccolta e nell'elaborazione delle stringhe nella libreria standard. Per fortuna c'è Kryo, ma è dipendenza e bisogna prima trovarla. Questo è il modo in cui avrebbe dovuto essere eseguita la serializzazione integrata.
dmitry

20

Non tutto è realmente serializzabile. Prendi una connessione tramite presa di rete, ad esempio. Potresti serializzare i dati / lo stato del tuo oggetto socket, ma l'essenza di una connessione attiva andrebbe persa.


Questo sarebbe il mio problema e se non fossi abbastanza intelligente da provare a serializzare il socket, troverei il mio errore durante il debug. Tuttavia, ora mi trovo in una situazione in cui non posso usare la serializzazione Java a causa della classe di terze parti che non implementa Serializable senza una buona ragione.
Yoni Roit

4
Ci sono alcuni modi decenti per gestire questo caso, come scrivere una classe wrapper Serializable che sappia leggere e scrivere i dati chiave della classe di terze parti; rendere transitoria l'istanza avvolta e sovrascrivere writeObject e readObject.
Greg Case

Puoi ereditare dagli oggetti richiesti nella tua API e serializzare quelle classi?
Joel Coehoorn

@ Joel: è una buona idea, ma è comunque un trucco. Immagino che l'intera faccenda sia solo un altro compromesso andato storto. Grazie per i tuoi commenti.
Yoni Roit

1
Questo è uno di quei rari esempi che dimostra che tutto ciò di cui abbiamo veramente bisogno è implements NotSerializable:)
Rob Grant

13

Il ruolo principale di Serializable in Java è quello di rendere effettivamente non serializzabili, per impostazione predefinita, tutti gli altri oggetti. La serializzazione è un meccanismo molto pericoloso, specialmente nella sua implementazione predefinita. Quindi, come l'amicizia in C ++, è disattivato per impostazione predefinita, anche se costa un po 'rendere le cose serializzabili.

La serializzazione aggiunge vincoli e potenziali problemi poiché la compatibilità della struttura non è assicurata. È positivo che sia disattivato per impostazione predefinita.

Devo ammettere che ho visto pochissime classi non banali in cui la serializzazione standard fa quello che voglio. Soprattutto nel caso di strutture dati complesse. Quindi lo sforzo che spenderesti per rendere la classe serializzabile correttamente riduce il costo dell'aggiunta dell'interfaccia.


9

Per alcune classi, specialmente quelle che rappresentano qualcosa di più fisico come un File, un Socket, un Thread o una connessione DB, non ha assolutamente senso serializzare le istanze. Per molti altri, la serializzazione può essere problematica perché distrugge i vincoli di unicità o semplicemente ti costringe a gestire istanze di diverse versioni di una classe, cosa che potresti non voler fare.

Probabilmente, sarebbe stato meglio rendere tutto Serializzabile per impostazione predefinita e rendere le classi non serializzabili tramite una parola chiave o un'interfaccia marker, ma poi, coloro che dovrebbero usare quell'opzione probabilmente non ci penserebbero. Così com'è, se devi implementare Serializable, ti verrà detto da un'eccezione.


4

Penso che il pensiero fosse quello di assicurarti che tu, come programmatore, sapessi che il tuo oggetto fosse serializzato.



1

Dovendo affermare esplicitamente che le istanze di una certa classe sono serializzabili, il linguaggio ti obbliga a pensare se dovresti permetterlo. Per semplici oggetti di valore la serializzazione è banale, ma nei casi più complessi è necessario riflettere davvero sulle cose.

Affidandoti semplicemente al supporto di serializzazione standard della JVM ti esponi a tutti i tipi di problemi di controllo delle versioni.

Unicità, riferimenti a risorse "reali", timer e molti altri tipi di artefatti NON sono candidati per la serializzazione.



0

Bene, la mia risposta è che questo non è per una buona ragione. E dai tuoi commenti posso vedere che l'hai già imparato. Altre lingue provano felicemente a serializzare tutto ciò che non salta su un albero dopo che hai contato fino a 10. Un oggetto dovrebbe essere serializzabile per impostazione predefinita.

Quindi, quello che devi fare fondamentalmente è leggere tu stesso tutte le proprietà della tua classe di terze parti. Oppure, se questa è un'opzione per te: decompila, metti lì la dannata parola chiave e ricompila.


2
La serializzazione aggiunge vincoli e potenziali problemi poiché la compatibilità della struttura non è assicurata. IMHO, è bene che sia disattivato per impostazione predefinita.
Uri

Non sono sicuro di cosa intendi per "compatibilità di struttura".
nes1983

0

Ci sono alcune cose in Java che semplicemente non possono essere serializzate perché sono specifiche del runtime. Cose come stream, thread, runtime, ecc. E anche alcune classi GUI (che sono connesse al sistema operativo sottostante) non possono essere serializzate.


0

Anche se sono d'accordo con i punti esposti in altre risposte qui, il vero problema è con la deserializzazione: se la definizione di classe cambia, c'è il rischio reale che la deserializzazione non funzioni. Non modificare mai i campi esistenti è un impegno piuttosto importante per l'autore di una libreria! Mantenere la compatibilità API è già un lavoro ingrato.


Questo non è corretto. È necessario leggere il capitolo Controllo delle versioni degli oggetti serializzabili della specifica di serializzazione degli oggetti, che non esisterebbe se ciò che affermi qui fosse vero. La definizione della classe può cambiare entro limiti piuttosto ampi prima che diventi incompatibile con le serializzazioni precedenti. E certamente non è la risposta alla domanda. La vera ragione ha a che fare con problemi di sicurezza.
Marchese di Lorne

@EJP, nell'interesse della verità ho modificato la mia risposta per riflettere i tuoi punti. Il sentimento è comunque, è un grande impegno che dovrebbe essere sicuramente opt-in piuttosto che opt-out
CurtainDog

0

Una classe che deve essere mantenuta su un file o su un altro supporto deve implementare l'interfaccia Serializable, in modo che JVM possa consentire la serializzazione dell'oggetto classe. Perché la classe Object non è serializzata, nessuna delle classi ha bisogno di implementare l'interfaccia, dopotutto JVM serializza la classe solo quando uso ObjectOutputStream, il che significa che il controllo è ancora nelle mie mani per consentire alla JVM di serializzare.

Il motivo per cui la classe Object non è serializzabile per impostazione predefinita è il fatto che la versione della classe è il problema principale. Pertanto ogni classe interessata alla serializzazione deve essere contrassegnata come Serializable in modo esplicito e fornire un numero di versione serialVersionUID.

Se serialVersionUID non viene fornito, si ottengono risultati imprevisti durante la deserializzazione dell'oggetto, motivo per cui JVM lancia InvalidClassException se serialVersionUID non corrisponde. Pertanto ogni classe deve implementare l' interfaccia Serializable e fornire serialVersionUID per assicurarsi che la classe presentata ad entrambe le estremità sia identica.

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.