Pregunta

En Java, si una clase implementa Serializable, pero es abstracto, en caso de tener un serialVersionUID declarado largo, o hacer las subclases que sólo requieren?

En este caso, es de hecho la intención de que todas las subclases ocupan de serialización como el propósito del tipo se va a utilizar en RMI llama.

¿Fue útil?

Solución

El serialVersionUID se proporciona para determinar la compatibilidad entre un objeto deseralized 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. Usted nunca tendrá una instancia de esa clase abstracta para serializar / deserializar, por lo que no necesita un serialVersionUID.

(Por supuesto, esto generará una advertencia del compilador, que desea quitarse de encima, ¿verdad?)

Resulta comentario de James es correcta. El serialVersionUID de una clase base abstracta no get propaga a las subclases. A la luz de esto, DO necesitan la serialVersionUID en su clase base.

El código de prueba:

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() );
    }
}

Ejecutar el principal Sub vez para conseguirlo para crear y guardar un objeto. A continuación, cambiar el serialVersionUID en la clase base, comente todas las líneas en las que salvan el principal objeto (por lo que no guarda otra vez, lo que desea es cargar el viejo), y ejecutarlo de nuevo. Esto dará lugar a una excepción

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

Otros consejos

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

Hay otras opciones si usted está tratando de hacer algo de fantasía. No estoy seguro de lo que quiere decir con "es la intención de las clases sub ...". ¿Vas a escribir métodos de serialización personalizado (por ejemplo. WriteObject, readObject)? Si es así, hay otras opciones para hacer frente a una superclase.

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

HTH Tom

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

  

Si una clase serializable no declara explícitamente una   serialVersionUID, entonces el tiempo de ejecución de serialización calculará una   serialVersionUID valor por defecto para esa clase en base a varios aspectos   de la clase ...

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

Conceptualmente, los datos serializados este aspecto:

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

Así que cuando deserializar, falta de coincidencia en la versión en cualquiera de las clases en la jerarquía hace que la deserialización a fallar. Nada se almacena para las interfaces, así que no hay necesidad de especificar la versión de ellos.

Respuesta: sí, sí es necesario para proporcionar serialVersionUID en la clase abstracta de base también. 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 campo nuevo), que está establecido en 0 / falso / null (no al valor por defecto, como cabría esperar).
  3. si un campo de tipo de datos cambia, el valor deserializado debe poder asignar al nuevo tipo. P.ej. si tuviera un campo Object con valor String, cambiando el tipo de campo a String tendrá éxito, pero cambiando a Integer no lo hará. Sin embargo, el cambio de campo de int a long no funcionará, aunque se puede asignar un valor a int long variable.
  4. Si subclase ya no se extiende la clase padre, la que se extiende en los datos serializados, se ignora (como en el caso 1).
  5. Si una subclase ahora se extiende una clase, que no se encuentra en los datos serializados, campos de clase de padres son restauradas con 0 / valor falso / null (como en el caso 2).

En palabras sencillas: se puede cambiar el orden de los campos, agregar y quitar ellos, incluso cambiar la jerarquía de clases. No se debe cambiar el nombre de los campos o clases (que no fallará, pero los valores no se deserializado). No se puede cambiar el tipo de campos con tipo primitivo, y se puede cambiar los campos de tipo de referencia siempre que el nuevo tipo es asignable de todos los valores.

Nota:. Si la clase base no implementa Serializable y sólo la subclase, a continuación, los campos de la clase base se comportaría como transient

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top