una tener que puede poo persona legislador interfaces herede ejemplo declara constructores clases clase atributos abstractas abstracta java serialization abstract-class serialversionuid

java - que - Debe una clase abstracta tener un serialVersionUID



una clase abstracta puede tener atributos (4)

Conceptualmente, los datos serializados se ven así:

subClassData(className + version + fieldNames + fieldValues) parentClassData(className + version + fieldNames + fieldValues) ... (up to the first parent, that implements Serializable)

Por lo tanto, cuando se deserializa, la falta de coincidencia en la versión en cualquiera de las clases de la jerarquía hace que la deserialización falle. No se almacena nada para las interfaces, por lo que no es necesario especificar la versión para ellas.

Respuesta: sí, también necesita proporcionar serialVersionUID en la clase abstracta base. Incluso si no tiene campos ( className + version se almacenan incluso si no hay campos).

También tenga en cuenta lo siguiente:

  1. Si la clase no tiene un campo, que se encuentra en los datos serializados (un campo eliminado), se ignora.
  2. Si la clase tiene un campo, que no está presente en los datos serializados (un nuevo campo), se establece en 0 / falso / nulo (no en el valor predeterminado como cabría esperar).
  3. si un campo cambia de tipo de datos, el valor deserializado debe ser asignable al nuevo tipo. Por ejemplo, si tiene un campo Object con valor de String , cambiar el tipo de campo a String tendrá éxito, pero cambiar a Integer no lo hará. Sin embargo, cambiar el campo de int a long no funcionará, aunque puede asignar el valor int a la variable long .
  4. Si la subclase ya no extiende la clase padre, que se extiende en los datos serializados, se ignora (como en el caso 1).
  5. Si una subclase ahora amplía una clase, que no se encuentra en datos serializados, los campos de la clase padre se restauran con 0 / false / null value (como en el caso 2).

En palabras simples: puede reordenar campos, agregarlos y eliminarlos, incluso cambiar la jerarquía de clases. No debe cambiar el nombre de los campos o las clases (no fallará, pero los valores no se deserializarán). No puede cambiar el tipo de campo con el tipo primitivo, y puede cambiar los campos de tipo de referencia, siempre que el nuevo tipo se pueda asignar a todos los valores.

Nota: si la clase base no implementa Serializable y solo la subclase sí lo hace, los campos de la clase base se comportarán como transient .

En java, si una clase implementa Serializable pero es abstracta, ¿debería tener un serialVersionUID declarado por mucho tiempo, o las subclases solo lo requieren?

En este caso, de hecho, la intención es que todas las subclases se ocupen de la serialización, ya que el objetivo del tipo es utilizarlo en llamadas RMI.


El serialVersionUID se proporciona para determinar la compatibilidad entre un objeto deselacionado y la versión actual de la clase. Como tal, no es realmente necesario en la primera versión de una clase, o en este caso, en una clase base abstracta. Nunca tendrá una instancia de esa clase abstracta para serializar / deserializar, por lo que no necesita un serialVersionUID.

(Por supuesto, genera una advertencia del compilador, de la que desea deshacerse, ¿verdad?)

Resulta que el comentario de James es correcto. El serialVersionUID de una clase base abstracta se propaga a subclases. A la luz de eso, necesitas el serialVersionUID en tu clase base.

El código para probar:

import java.io.Serializable; public abstract class Base implements Serializable { private int x = 0; private int y = 0; private static final long serialVersionUID = 1L; public String toString() { return "Base X: " + x + ", Base Y: " + y; } } import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class Sub extends Base { private int z = 0; private static final long serialVersionUID = 1000L; public String toString() { return super.toString() + ", Sub Z: " + z; } public static void main(String[] args) { Sub s1 = new Sub(); System.out.println( s1.toString() ); // Serialize the object and save it to a file try { FileOutputStream fout = new FileOutputStream("object.dat"); ObjectOutputStream oos = new ObjectOutputStream(fout); oos.writeObject( s1 ); oos.close(); } catch (Exception e) { e.printStackTrace(); } Sub s2 = null; // Load the file and deserialize the object try { FileInputStream fin = new FileInputStream("object.dat"); ObjectInputStream ois = new ObjectInputStream(fin); s2 = (Sub) ois.readObject(); ois.close(); } catch (Exception e) { e.printStackTrace(); } System.out.println( s2.toString() ); } }

Ejecute el principal en Sub una vez para que cree y guarde un objeto. Luego cambie el serialVersionUID en la clase Base, comente las líneas en main que guardan el objeto (para que no lo guarde de nuevo, solo quiera cargar el anterior) y ejecútelo nuevamente. Esto dará como resultado una excepción

java.io.InvalidClassException: Base; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2


En realidad, señalando el enlace de Tom si falta serialVersionID realidad se calcula por el tiempo de ejecución de serialización, es decir, no durante la compilación

Si una clase serializable no declara explícitamente un serialVersionUID, el tiempo de ejecución de serialización calculará un valor serialVersionUID predeterminado para esa clase en función de varios aspectos de la clase ...

Esto hace las cosas aún más complicadas teniendo diferentes versiones de JRE.


Sí, en general, por la misma razón que cualquier otra clase necesita una identificación de serie para evitar que se genere una. Básicamente, cualquier clase (no interfaz) que implementa serializable debe definir el ID de la versión en serie o corre el riesgo de errores de serialización cuando la misma compilación .class no está en el servidor y las JVM del cliente.

Hay otras opciones si estás tratando de hacer algo elegante. No estoy seguro de a qué te refieres con "es la intención de las subclases ...". ¿Vas a escribir métodos de serialización personalizados (por ejemplo, writeObject, readObject)? Si es así, hay otras opciones para lidiar con una súper clase.

ver: http://java.sun.com/javase/6/docs/api/java/io/Serializable.html

HTH Tom