2011-08-22 19 views
17

El siguiente código:¿Por qué una clase interna serializable no es serializable?

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; 

    } 

} 

desencadena la siguiente excepción:

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

supongo que la clase interna tiene un campo TestInnerClass.this que le permite el acceso privado a TestInnerClass 's campos y métodos. Declarando la clase interna estática solves it, pero ¿qué pasa si InnerClass necesita este acceso? ¿Hay alguna forma de serializar una clase interna no estática sin la clase adjunta, p. haciendo la referencia a la clase externa transient?

editar: por ejemplo, el acceso a la clase externa podría ser necesario solo antes de la serialización. OK, el compilador no puede saber eso, pero pensé que esa es la razón por la cual existe la palabra clave transient.

+4

¿trató de declarar la clase interna estática? 'private static class InnerClass' – gnat

Respuesta

20

lo que si necesita InnerClass este acceso?

Luego necesita la instancia de clase externa, y debe ser serializada junto con la clase interna.

¿Hay alguna manera de serializar una clase interna no estática sin la clase adjunta, p. Ej. haciendo transitoria la referencia a la clase externa?

No. ¿Qué pasaría cuando deserialice una clase así y luego intente llamar a un método de instancia de la clase externa? A NullPointerException?

+1

En mi situación, la clase interna necesita acceso antes de que realmente se serialice (no después de la deserialización). Posteriormente, solo se utiliza como una superclase que no conoce la clase externa. – tb189

+5

@ tb189: siempre se puede romper la dependencia no estática añadiendo un campo 'transient TestInnerClass parentClass' a' InnerClass' y cuidarlo cuando se deserializa. –

+0

Esa sería, de hecho, una forma de manejarlo, y se parece a una referencia transitoria al 'TestInnerClass.this'. – tb189

1

¿qué tal hacer TestInnerClass serializable?

public class TestInnerClass implements Serializable { } 
+2

Eso es posible, pero no siempre se desea, ya que eso agrega una gran cantidad de datos a la clase serializada. – tb189

+0

@EJP: siempre hay soluciones que podrían ser más preferibles (separar las partes de la clase interna que necesitan acceso y luego reenviarla a una clase serializable estática, utilizando un campo transitorio TestInnerClass, manteniendo otro objeto serializable en la clase interna). También implicaría declarar transitorios todos los campos de la clase externa, lo que parece un defecto de diseño. No es porque la situación actual no funcione, la primera alternativa/hack debería usarse inmediatamente. – tb189

0

InnerClass no se pueden serializar porque instanciarlo (según sea necesario durante la deserialización) que necesita una referencia a una instancia de la clase externa no pueden existir

Las instancias de clases internas sin una instancia de la clase externa.

es decir

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

Si utiliza la clase interna estática, será posible serializar la clase interna estática. Las instancias de clases internas estáticas se pueden crear de forma independiente.

es decir

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

Quizás sería agradable hacer una esencia de Github o un ejemplo completamente reproducible, ¿no crees? – Adonis

Cuestiones relacionadas