2011-08-22 6 views
17

Il seguente codice:Perché una classe interna serializzabile non è serializzabile?

public class TestInnerClass { 

    public static void main(String[] args) throws IOException { 
     new TestInnerClass().serializeInnerClass(); 
    } 

    private void serializeInnerClass() throws IOException { 
     File file = new File("test"); 
     InnerClass inner = new InnerClass(); 
     new ObjectOutputStream(new FileOutputStream(file)).writeObject(inner); 
    } 

    private class InnerClass implements Serializable { 

     private static final long serialVersionUID = 1L; 

    } 

} 

genera la seguente eccezione:

Exception in thread "main" java.io.NotSerializableException: TestInnerClass 

Credo che la classe interna ha un campo TestInnerClass.this che permette l'accesso privato a TestInnerClass s' campi e metodi. Dichiarando la classe interna statica solves it, ma cosa succede se InnerClass ha bisogno di questo accesso? Esiste un modo per serializzare una classe interna non statica senza la classe di inclusione, ad es. facendo riferimento alla classe esterna transient?

modifica: ad esempio, l'accesso alla classe esterna potrebbe essere necessario solo prima della serializzazione. OK, il compilatore non può saperlo, ma ho pensato che fosse il motivo per cui esiste la parola chiave transient.

+4

Hai provato a dichiarare la classe interna statica? 'Classe statica privata InnerClass' – gnat

risposta

20

cosa succede se classe interna ha bisogno di questo accesso?

Quindi ha bisogno dell'istanza di classe esterna e deve essere serializzata insieme alla classe interna.

C'è un modo per serializzare una classe interna non statica senza la classe di inclusione, ad es. facendo riferimento al transitorio di classe esterna?

No. Che cosa accadrebbe quando deserializzi una classe del genere e poi provi a chiamare un metodo di istanza della classe esterna? A NullPointerException?

+1

Nella mia situazione, la classe interna ha bisogno di accesso prima che sia effettivamente serializzata (non dopo la deserializzazione). In seguito viene utilizzato solo come una superclasse che non conosce la classe esterna. – tb189

+5

@ tb189: È sempre possibile interrompere la dipendenza non statica aggiungendo un campo 'transient TestInnerClass parentClass' a' InnerClass' e averne cura durante la deserializzazione. –

+0

Questo sarebbe davvero un modo per affrontarlo e assomiglia ad un riferimento transitorio al 'TestInnerClass.this'. – tb189

1

come rendere serializza TestInnerClass?

public class TestInnerClass implements Serializable { } 
+2

Ciò è possibile, ma non sempre desiderato, poiché aggiunge molti dati alla classe serializzata. – tb189

+0

@EJP: ci sono sempre soluzioni che potrebbero essere più preferibili (separando le parti della classe interna che richiedono accesso e quindi inoltrandole a una classe serializzabile statica, utilizzando un campo transitorio TestInnerClass, mantenendo un altro oggetto serializzabile nella classe interna). Significherebbe anche dichiarare tutti i campi nel transitorio di classe esterna, che sembra un difetto di progettazione. Non è perché la situazione attuale non funziona che dovrebbe essere immediatamente utilizzata la prima alternativa/hack. – tb189

0

classe interna non possono essere serializzati perché per istanziare (come richiesto durante la deserializzazione) è necessario un riferimento a un'istanza della classe esterna non possono esistere

istanze di classi interne senza un'istanza della classe esterna.

cioè

OuterClass o = new OuterClass(); 
OuterClass.InnerClass o_i = o.new InnerClass(); 

Se si utilizza classe interna statica, sarà possibile puntate classe interna statica. Le istanze di classi interne statiche possono essere create autonomamente.

cioè

OuterClass o = new OuterClass(); 
OuterClass.InnerClass i = new OuterClass.InnerClass(); 
+0

Forse fare un esempio Github o un esempio completo riproducibile sarebbe bello, non credi? – Adonis