Domanda Che cos'è un serialVersionUID e perché dovrei usarlo?


Eclipse emette avvisi quando a serialVersionUID manca.

La classe serializzabile Foo non dichiara una finale statica   campo serialVersionUID di tipo long

Cosa è serialVersionUID e perché è importante? Si prega di mostrare un esempio in cui manca serialVersionUID causerà un problema


2481
2017-11-12 23:24


origine


risposte:


I documenti per java.io.Serializable sono probabilmente una buona spiegazione come si otterrà:

Il runtime di serializzazione si associa   con ogni classe serializzabile una versione   numero, chiamato serialVersionUID,   che viene utilizzato durante la deserializzazione   per verificare che il mittente e il destinatario   di un oggetto serializzato hanno caricato   classi per quell'oggetto che sono   compatibile rispetto a   serializzazione. Se il ricevitore ha   caricato una classe per l'oggetto che ha   un serialVersionUID diverso da quello   della classe del mittente corrispondente,   allora la deserializzazione si tradurrà in un    InvalidClassException. Un serializzabile   la classe può dichiarare la propria   serialVersionUID esplicitamente da   dichiarando un campo chiamato   "serialVersionUID" deve essere   statico, finale e di tipo long:

ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;

Se un   la classe serializzabile non esplicitamente   dichiarare un serialVersionUID, quindi il   il runtime di serializzazione calcolerà a   valore serialVersionUID predefinito per   quella classe basata su vari aspetti di   la classe, come descritto nel   Serializzazione di oggetti Java (TM)   Specification. Tuttavia, lo è fortemente   consigliato tutto serializzabile   le classi dichiarano esplicitamente   valori serialVersionUID, dal momento che   calcolo serialVersionUID predefinito   è molto sensibile ai dettagli della classe   che può variare a seconda del compilatore   implementazioni, e può quindi risultare   inaspettato InvalidClassExceptions   durante la deserializzazione. Pertanto, a   garantire una coerenza   valore serialVersionUID attraverso   diverso compilatore java   implementazioni, una classe serializzabile   deve dichiarare un esplicito   valore serialVersionUID. È altresì   fortemente consigliato che esplicito   le dichiarazioni serialVersionUID usano il   modificatore privato ove possibile, dal   tali dichiarazioni si applicano solo al   dichiarando immediatamente   i campi class - serialVersionUID non lo sono   utile come membri ereditati.


1909
2017-11-12 23:30



Se stai serializzando solo perché devi serializzare per il bene dell'implementazione (a chi importa se serializzi per un HTTPSession, per esempio ... se è memorizzato o meno, probabilmente non ti interessa la serializzazione di un oggetto modulo) , quindi puoi ignorarlo.

Se si utilizza effettivamente la serializzazione, è importante solo se si pianifica di archiviare e recuperare oggetti utilizzando direttamente la serializzazione. SerialVersionUID rappresenta la versione della tua classe e dovresti incrementarla se la versione corrente della tua classe non è retrocompatibile con la sua versione precedente.

La maggior parte delle volte, probabilmente non utilizzerai la serializzazione direttamente. In questo caso, genera un UID serializzabile predefinito facendo clic sull'opzione di correzione rapida e non preoccuparti.


415
2017-11-13 04:24



Non posso perdere questa occasione per collegare il libro di Josh Bloch Efficace Java (2a edizione). Il capitolo 11 è una risorsa indispensabile sulla serializzazione Java.

Per Josh, l'UID generato automaticamente viene generato sulla base di un nome di classe, interfacce implementate e tutti i membri pubblici e protetti. Cambiare qualcuno di questi in qualsiasi modo cambierà il serialVersionUID. Quindi non è necessario pasticciarli solo se si è certi che non verrà serializzata più di una versione della classe (tra processi o recuperati dallo storage in un momento successivo).

Se li ignori per ora, e scopri in seguito che hai bisogno di cambiare la classe in qualche modo, ma mantieni la compatibilità con la vecchia versione della classe, puoi usare lo strumento JDK serialver generare il serialVersionUID sul vecchio classe, e impostato esplicitamente sulla nuova classe. (A seconda delle modifiche, potrebbe essere necessario implementare anche la serializzazione personalizzata aggiungendo writeObject e readObject metodi - vedi Serializable javadoc o il capitolo 11 di cui sopra)


263
2017-11-12 23:37



Puoi dire a Eclipse di ignorare questi avvisi di serialVersionUID:

Finestra> Preferenze> Java> Compilatore> Errori / Avvisi> Potenziali problemi di programmazione

Nel caso in cui non lo sapessi, ci sono molti altri avvisi che puoi abilitare in questa sezione (o anche alcuni di quelli segnalati come errori), molti sono molto utili:

  • Potenziali problemi di programmazione: Possibile assegnazione booleana accidentale
  • Potenziali problemi di programmazione: accesso al puntatore nullo
  • Codice non necessario: la variabile locale non viene mai letta
  • Codice non necessario: controllo null ridondante
  • Codice non necessario: cast non necessario o 'instanceof'

e molti altri.


124
2017-11-13 01:17



serialVersionUID facilita il controllo delle versioni dei dati serializzati. Il suo valore è memorizzato con i dati durante la serializzazione. Quando si deserializza, viene verificata la stessa versione per vedere come i dati serializzati corrispondono al codice corrente.

Se vuoi modificare i tuoi dati, normalmente inizi con a serialVersionUID di 0, e confrontalo con ogni modifica strutturale alla tua classe che altera i dati serializzati (aggiungendo o rimuovendo campi non transitori).

Il meccanismo di de-serializzazione incorporato (in.defaultReadObject()) si rifiuterà di deserializzare da vecchie versioni dei dati. Ma se vuoi puoi definire il tuo readObject ()-funzione che può leggere i vecchi dati. Questo codice personalizzato può quindi controllare il serialVersionUID per sapere in quale versione si trovano i dati e decidere come deserializzarli. Questa tecnica di versioning è utile se memorizzi dati serializzati che sopravvivono a diverse versioni del tuo codice.

Ma la memorizzazione di dati serializzati per un così lungo periodo di tempo non è molto comune. È molto più comune utilizzare il meccanismo di serializzazione per scrivere temporaneamente dati ad esempio su una cache o inviarli tramite la rete a un altro programma con la stessa versione delle parti rilevanti della base di codice.

In questo caso non sei interessato a mantenere la retrocompatibilità. Ti preoccupi solo di assicurarti che le basi di codice che comunicano abbiano effettivamente le stesse versioni delle classi pertinenti. Al fine di facilitare tale controllo, è necessario mantenere il serialVersionUIDproprio come prima e non dimenticare di aggiornarlo quando apporti modifiche alle tue classi.

Se ti dimentichi di aggiornare il campo, potresti finire con due versioni diverse di una classe con struttura diversa ma con la stessa serialVersionUID. Se ciò accade, il meccanismo predefinito (in.defaultReadObject()) non rileverà alcuna differenza e tenterà di declassare i dati incompatibili. Ora si potrebbe finire con un errore di runtime criptico o un errore silenzioso (campi nulli). Questi tipi di errori potrebbero essere difficili da trovare.

Quindi, per aiutare questo usecase, la piattaforma Java offre una scelta di non impostare il serialVersionUID manualmente. Invece, un hash della struttura di classe verrà generato in fase di compilazione e utilizzato come id. Questo meccanismo farà in modo di non avere mai strutture di classi diverse con lo stesso id e quindi non otterrete questi errori di serializzazione di runtime hard-to-trace citati sopra.

Ma c'è un retro della strategia di identificazione generata automaticamente. Vale a dire che gli ID generati per la stessa classe potrebbero differire tra i compilatori (come menzionato sopra da Jon Skeet). Quindi se comunichi i dati serializzati tra il codice compilato con diversi compilatori, si consiglia comunque di mantenere gli id ​​manualmente comunque.

E se sei retrocompatibile con i tuoi dati come nel caso di primo utilizzo menzionato, probabilmente vorresti anche tu mantenere l'id da solo. Questo al fine di ottenere id leggibili e avere un maggiore controllo su quando e come cambiano.


96
2017-10-03 06:05



Cos'è un serialVersionUID e perché dovrei usarlo?

SerialVersionUID è un identificativo univoco per ogni classe, JVM lo usa per confrontare le versioni della classe assicurando che sia stata utilizzata la stessa classe durante il caricamento della serializzazione durante la deserializzazione.

Specificarne uno dà più controllo, anche se JVM ne genera uno se non lo si specifica. Il valore generato può variare tra diversi compilatori. Inoltre, a volte si desidera solo per qualche motivo proibire la deserializzazione di vecchi oggetti serializzati [backward incompatibility], e in questo caso devi solo cambiare serialVersionUID.

Il javadocs per Serializable dire:

il calcolo predefinito di serialVersionUID è molto sensibile alla classe   dettagli che possono variare a seconda delle implementazioni del compilatore e possono   quindi risultato inaspettato InvalidClassExceptions durante   deserializzazione.

Pertanto, è necessario dichiarare serialVersionUID perché ci dà più controllo.

Questo articolo ha alcuni punti positivi sull'argomento.


61
2017-10-17 04:28



La domanda originale ha chiesto "perché è importante" e "esempio" dove questo Serial Version ID sarebbe utile Bene, ho trovato uno.

Diciamo che crei a Car class, istanziarlo e scriverlo su un flusso di oggetti. L'oggetto appiattito si trova nel file system per un po 'di tempo. Nel frattempo, se il Car la classe viene modificata aggiungendo un nuovo campo. Più tardi, quando provi a leggere (cioè deserializzare) l'appiattito Car oggetto, ottieni il java.io.InvalidClassException - poiché a tutte le classi serializzabili viene automaticamente assegnato un identificatore univoco. Questa eccezione viene generata quando l'identificatore della classe non è uguale all'identificatore dell'oggetto appiattito. Se ci pensi veramente, l'eccezione viene generata a causa dell'aggiunta del nuovo campo. È possibile evitare che questa eccezione venga generata controllando il controllo delle versioni dichiarando un serialVersionUID esplicito. C'è anche un piccolo vantaggio prestazionale nel dichiarare esplicitamente il tuo serialVersionUID(perché non deve essere calcolato). Pertanto, è consigliabile aggiungere il proprio serialVersionUID alle classi Serializable non appena le crei come mostrato di seguito:

public class Car {
static final long serialVersionUID = 1L; //assign a long value
}

41
2018-04-07 10:43



Se ricevi questo avvertimento in un corso, non pensi mai alla serializzazione e non ti dichiari implements Serializable, è spesso perché hai ereditato da una superclasse, che implementa Serializable. Spesso quindi sarebbe meglio delegare a tale oggetto invece di usare l'ereditarietà.

Quindi, invece di

public class MyExample extends ArrayList<String> {

    public MyExample() {
        super();
    }
    ...
}

fare

public class MyExample {
    private List<String> myList;

    public MyExample() {
         this.myList = new ArrayList<String>();
    }
    ...
}

e nei metodi rilevanti chiama myList.foo() invece di this.foo() (o super.foo()). (Questo non si adatta in tutti i casi, ma ancora abbastanza spesso.)

Vedo spesso persone che estendono JFrame o simili, quando hanno solo bisogno di delegare a questo. (Questo aiuta anche a completare automaticamente in un IDE, poiché JFrame ha centinaia di metodi, che non ti servono quando vuoi chiamare quelli personalizzati nella tua classe.)

Un caso in cui l'avvertenza (o serialVersionUID) è inevitabile è quando si estrae da AbstractAction, normalmente in una classe anonima, solo aggiungendo il metodo actionPerformed. Penso che non ci dovrebbe essere un avvertimento in questo caso (dato che normalmente non è possibile serializzare e deserializzare tali classi anonime in tutte le versioni della tua classe), ma non sono sicuro di come il compilatore possa riconoscerlo.


33
2018-02-03 00:32



Se non avrai mai bisogno di serializzare i tuoi oggetti su array di byte e inviarli / memorizzarli, non dovrai preoccuparti di questo. Se lo fai, allora devi considerare il tuo serialVersionUID poiché il deserializzatore dell'oggetto lo abbinerà alla versione dell'oggetto che ha il suo classloader. Maggiori informazioni su questo argomento nella specifica del linguaggio Java.


30
2017-11-12 23:30