2009-11-02 23 views
13

Ho una classe destinata all'uso immutabile, quindi desidero etichettare tutti i campi final.Oggetti serializzabili e immutabili

Tuttavia, la classe viene serializzata e deserializzata per l'invio in rete. Perché ciò funzioni è necessario un costruttore vuoto. Questo mi impedisce di creare i campi finali.

Sono sicuro che questo è un problema abbastanza comune ma non riesco a trovare una soluzione. Come dovrei procedere?

risposta

7

Nel tipico caso di serializzazione, non è richiesto che la classe abbia un costruttore vuoto o campi non finali da serializzare.

Ora, se si deve fare la propria serializzazione, o è necessario sottoclasse una classe che non implementa Serializable, questa è una storia diversa.

Quindi è necessario fornire ulteriori dettagli su come si sta avendo un problema.

+1

Grazie, stavo usando il metodo tipico di serializzazione, ma avevano sempre fornito un costruttore vuoto come fu così ho pensato che ha funzionato. – Pool

6

Un costruttore no-arg non è richiesto. La classe non serializzabile più derivata ha bisogno di un costruttore no-arg disponibile per la classe serializzabile meno avanzata.

Se è necessario modificare i campi all'interno di readObject, utilizzare un proxy seriale tramite readResolve e writeReplace.

5

Questo problema è un open bug on the Java language. (Si noti che questo si applica solo se si deve eseguire la serializzazione manualmente, come con readObject)

+0

Dalla valutazione: "il problema si applica ai campi dell'istanza finale diversi dai campi serializzabili della classe", quindi nel caso standard funziona correttamente. Nick sembra stia facendo qualcosa di diverso. – Yishai

+0

Ah sì, dovrei aggiungere una dichiarazione di non responsabilità che si applica solo se devi collegarti a readObject o qualcosa del genere. –

3

Per riprendere ciò che è stato detto, i costruttori no-arg non sono un requisito se si sta prendendo il percorso di implementazione dell'interfaccia java.io.Serializable . Date un'occhiata al codice sorgente java.lang.Integer per esempio, una semplice classe serializzabile/immutabile che ha due costruttori: uno che prende un int e uno che accetta una stringa. Codice sorgente: http://www.docjar.com/html/api/java/lang/Integer.java.html. Javadoc: http://java.sun.com/javase/6/docs/api/java/lang/Integer.html.

Inoltre, a seconda della complessità della classe e di ciò che si sta facendo, è possibile prendere in considerazione l'implementazione della serializzazione tramite l'interfaccia java.io.Externalizable (anche se alcuni la considerano obsoleta e richiede un costruttore no-arg). Ecco una panoramica su SO: What is the difference between Serializable and Externalizable in Java?, ed ecco il tutorial Java ufficiale: http://java.sun.com/docs/books/tutorial/javabeans/persistence/index.html.

3

Per la cronaca, da quando ho avuto un problema simile:
Ho avuto un messaggio "java.io.InvalidClassException: com.example.stuff.FooBar; com.example.stuff.FooBar; nessun costruttore valida"

Ho pensato che fosse perché mancava un costruttore predefinito. Ma le risposte sopra confermano che non è obbligatorio (ma la nostra app utilizza un vecchio serializzatore che richiede effettivamente un costruttore predefinito, quindi il caso può sorgere).

poi ho trovato una pagina affermando:

Se una classe che è stato progettato per l'eredità non è serializzabile, è potrebbe essere impossibile scrivere una sottoclasse serializzabile. In particolare, è impossibile se la superclasse non fornisce un costruttore senza parametri accessibile.

Da qui il messaggio che ho ricevuto, suppongo.Sembrava che la questione centrale fosse classica: ho dichiarato una classe come serializzabile, ma la superclasse no! Ho spostato l'interfaccia Serializable nella gerarchia, e tutto andava bene.

Ma il messaggio era un po 'fuorviante ... :-)

0

Un costruttore no-arg non è necessaria. Leggiamo il codice sorgente:

// java.io.ObjectStreamClass 
private static Constructor<?> getSerializableConstructor(Class<?> cl) { 
    Class<?> initCl = cl; 
    while (Serializable.class.isAssignableFrom(initCl)) { 
     if ((initCl = initCl.getSuperclass()) == null) { 
      return null; 
     } 
    } 
    ... 
} 

Quindi, in realtà il costruttore no-arg è necessario nel più vicino non Serializable classe nella gerarchia tipo.

Significa che la seguente classe Domain può essere serializzata.

class Domain implements Serializable { 
    private final int a; 

    public Domain(int a) { 
     this.a = a; 
    } 
} 

Ma la classe Son non può:

class Father{ 
    private final int a; 

    public Father(int a) { 
    this.a = a; 
    } 
} 

class Son extends Father implements Serializable { 
    public Son(int a) { 
    super(a); 
    } 
} 
Problemi correlati