uso - Java: ¿Cuándo agregar readObjectNoData() durante la serialización?
usar codigo html en java (4)
Estoy leyendo el capítulo de serialización en "Java efectivo". Estoy tratando de entender el párrafo a continuación en el libro.
Si implementa una clase con campos de instancia que sean serializables y ampliables, hay una advertencia que debe tener en cuenta. Si la clase tiene invariantes que se violarían si sus campos de instancia se inicializaran a sus valores predeterminados (cero para tipos integrales, falso para booleano y nulo para tipos de referencia de objeto), debe agregar este método readObjectNoData a la clase:
// readObjectNoData for stateful extendable serializable classes
private void readObjectNoData() throws InvalidObjectException {
throw new InvalidObjectException("Stream data required");
}
No estoy seguro de lo que significa la declaración anterior.
Para probar esto, creé una Persona de clase (tanto serializable como extensible)
class Person implements Serializable{
private String name;
private int age;
Person() {
this("default",1);
}
Person(String name, int y) {
this.name = name;
this.age = y;
}
}
y un empleado de la clase que lo extiende.
class Employee extends Person {
String address ;
public Employee()
{
super();
address ="default_address";
}
public Employee(String name , int age, String address)
{
super(name,age);
this.address = address;
}
}
¿Hay invariantes en la clase Person que creé? ¿Cuándo serán violados? Copié pegado el código para el método readObjectData () en la clase Employee, pero nunca se llamó. ¿Cuándo se llamará al método readObject ()? Me estoy perdiendo de algo ?
¿Hay invariantes en la clase Person que creé? ¿Cuándo serán violados?
Ninguno explícitamente, pero imagine que otros métodos en la clase asumen que el name
nunca es null
y arrojaría NullPointerException
si alguna vez lo fuera. En este caso, la no nulidad del name
es un invariante.
Copié el código para el método
readObjectData()
en la claseEmployee
, pero nunca se llamó. ¿Cuándo se llamará al métodoreadObject()
?
No hay ningún método readObjectData()
involucrado con la serialización, esto debe ser un error tipográfico. El método readObject()
cada vez que se deserializa un objeto serializado.
El método readObjectNoData()
es golpeado por algún caso de esquina oscuro al deserializar una subclase de la clase que contiene el método.
El artículo de serialización avanzada en el sitio web de Sun Oracle cubre el propósito de estos métodos de ayuda de serialización. Te sugiero que comiences allí y publiques cualquier pregunta posterior que te surja.
(actualizar)
En caso de que tenga curiosidad, se agregó el método readObjectNoData en la versión 1.4 para cubrir un caso de esquina que implica la adición de una superclase serializable a una clase serializable existente. Los detalles se pueden encontrar en la serialización de la especificación Serialización, 3.5 .
El texto referenciado es:
Para objetos serializables, el método readObjectNoData permite a una clase controlar la inicialización de sus propios campos en el caso de que una instancia de subclase se deserialice y la secuencia de serialización no enumere la clase en cuestión como una superclase del objeto deserializado. Esto puede ocurrir en casos donde la parte receptora usa una versión diferente de la clase de la instancia deserializada que la parte emisora, y la versión del receptor amplía las clases que no están extendidas por la versión del remitente. Esto también puede ocurrir si la secuencia de serialización ha sido manipulada; por lo tanto, readObjectNoData es útil para inicializar correctamente objetos deserializados a pesar de una secuencia fuente "hostil" o incompleta.
Entonces esto puede suceder en dos casos:
- La JVM que decodifica el flujo de objetos tiene una versión más nueva de la subclase que se está deserializando (
Employee
), una que extiende alguna clase principal (Person
). La JVM que originalmente * en * codificó la secuencia de objetos tiene una versión diferente y más antigua de estas clases, dondePerson
aún no era una superclase deEmployee
. - Alguien se metió intencionalmente con el flujo de objetos para romper cosas.
"Extensible" significa "puede tener una subclase".
readObjectNoData se usa en un caso inusual en el que el serializador (escritor) está trabajando con una versión de una clase sin clase base, mientras que el deserializador (lector) de la clase tiene una versión de la clase que está basada en una subclase. La subclase puede decir "está bien si mi clase base no está en los datos serializados, simplemente haga una vacía" implementando readObjectNoData. Vea estas notas de la versión .
La sección readObjectNoData en Java Object Serialization Specification parece interesante (ver a continuación).
Sus ediciones a la pregunta dan un ejemplo perfecto. Si Employee
se serialized
cuando no extendió Person
y más tarde se deserialized
cuando lo hizo, entonces la parte Person
se inicializaría para empty string y 0 age. Usando este método, puedes inicializarlos para "nombrar" y 1 respectivamente.
Para objetos serializables, el método readObjectNoData permite a una clase controlar la inicialización de sus propios campos en el caso de que una instancia de subclase se deserialice y la secuencia de serialización no enumere la clase en cuestión como una superclase del objeto deserializado. Esto puede ocurrir en casos donde la parte receptora usa una versión diferente de la clase de la instancia deserializada que la parte emisora, y la versión del receptor amplía las clases que no están extendidas por la versión del remitente. Esto también puede ocurrir si la secuencia de serialización ha sido manipulada; por lo tanto, readObjectNoData es útil para inicializar correctamente objetos deserializados a pesar de una secuencia fuente "hostil" o incompleta.
private void readObjectNoData() throws ObjectStreamException;
Cada clase serializable puede definir su propio método readObjectNoData. Si una clase serializable no define un método readObjectNoData, en las circunstancias enumeradas anteriormente, los campos de la clase se inicializarán a sus valores predeterminados (como se detalla en la sección 4.5.5 de La especificación del lenguaje JavaTM, Segunda edición); este comportamiento es coherente con el de ObjectInputStream anterior a la versión 1.4 del JavaTM 2 SDK, Standard Edition, cuando se introdujo el soporte para los métodos readObjectNoData. Si una clase serializable define un método readObjectNoData y surgen las condiciones antes mencionadas, readObjectNoData se invocará en el punto durante la deserialización cuando un método readObject definido por la clase se llamaría si la clase en cuestión hubiera sido listada por la secuencia como una superclase de la instancia siendo deserializada.
Una invariante en su clase de persona podría ser algo así como:
age must be greater than 0
Entonces, cuando la clase Person se instancia con el valor predeterminado, 0 (ver aquí: http://download.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html ) habrás violado ese invariante.
Sin embargo, dado el constructor predeterminado, estarás bien :)