2010-05-25 11 views
40

Tengo una clase que define un tipo de valor inmutable que ahora necesito serializar. La inmutabilidad proviene de los campos finales que se establecen en el constructor. Intenté serializar y funciona (¿sorprendentemente?), Pero no tengo idea de cómo.¿Cómo deserializa la serialización de java cuando no se especifica ningún constructor predeterminado?

He aquí un ejemplo de la clase

public class MyValueType implements Serializable 
{ 
    private final int value; 

    private transient int derivedValue; 

    public MyValueType(int value) 
    { 
     this.value = value; 
     this.derivedValue = derivedValue(value); 
    } 

    // getters etc... 
} 

Dado que la clase no tiene ningún constructor arg, ¿cómo puede ser instanciada y el conjunto final de campo?

(Un aparte -. Me di cuenta esta clase en particular debido idea no estaba generando una inspección "no serialVersionUID" de advertencia para esta clase, sin embargo, avisos generados con éxito para otras clases que simplemente he hecho serializable)

+0

Pregunta de bonificación: ¿cómo se serializa una instancia de una clase * anonymous *? – ewernli

+0

Supongo que es serializable solo si uno de sus supertipos es serializable y la clase adjunta es serializable. Eso parece tener sentido, pero nadie sabe qué hay en el JLS. – mdma

+0

No es 'nadie adivina qué hay en el JLS'. Está allí para ser leído por cualquiera. – EJP

Respuesta

34

La JVM implementa la deserialización en un nivel por debajo de las construcciones de lenguaje básicas. Específicamente, no llama a ningún constructor.

+2

En realidad, llama al constructor sin parámetros. Solo las clases con dicho constructor son serializables. – Oak

+11

@Oak. No es verdad. Puede serializar una clase sin un constructor predeterminado. –

+2

@Alexander: mi mal. Lo he confundido con el hecho de que las superclases no serializables a tipos serializables deben tener dicho constructor. – Oak

14

Dado que la clase no tiene un constructor no arg, ¿cómo se puede crear una instancia y se establece el campo final?

Se produce algo de magia negra desagradable. Hay una puerta trasera en la JVM que permite crear un objeto sin invocar ningún constructor. Los campos del nuevo objeto se inicializan primero a sus valores predeterminados (falso, 0, nulo, etc.) y luego el código de deserialización del objeto rellena los campos con los valores de la secuencia del objeto.

(Ahora que Java es de código abierto, se puede leer el código que hace esto ... y llorar!)

+4

De hecho, ni siquiera necesitas magia negra repugnante; la reflexión (por ejemplo, una desagradable magia gris;) se puede usar para establecer campos finales. Funciona siempre que los valores se establezcan antes de que los campos se lean la primera vez. – gustafc

+4

@gustafc - pero se necesita magia negra para crear el objeto sin ejecutar ningún constructor. –

11

Tanto Michael y Stephen le dio una excelente respuesta, sólo quiero advertirle sobre transient campos .

Si el valor predeterminado (null para las referencias, 0 para las primitivas) no es aceptable para ellos después de la deserialización, entonces debe proporcionar su versión de readObject e inicializarla allí.

private void readObject (
      final ObjectInputStream s 
     ) throws 
      ClassNotFoundException, 
      IOException 
    { 
     s.defaultReadObject(); 

     // derivedValue is still 0 
     this.derivedValue = derivedValue(value); 
    } 
+0

Gran comentario, gracias por el ejemplo. –

Cuestiones relacionadas