Pregunta ¿Qué es un serialVersionUID y por qué debería usarlo?


Eclipse emite advertencias cuando serialVersionUID Está perdido.

La clase serializable Foo no declara una final estática   campo serialVersionUID de tipo long

Que es serialVersionUID ¿y porque es importante? Por favor, muestre un ejemplo donde falta serialVersionUID causará un problema


2482
2017-11-12 23:24


origen


Respuestas:


Los documentos para java.io.Serializable son probablemente la mejor explicación que obtendrás:

El tiempo de ejecución de serialización se asocia   con cada clase serializable una versión   número, llamado serialVersionUID,   que se usa durante la deserialización   para verificar que el emisor y el receptor   de un objeto serializado han cargado   clases para ese objeto que son   compatible con respecto a   publicación por entregas. Si el receptor tiene   cargó una clase para el objeto que tiene   un serialVersionUID diferente que ese   de la clase del remitente correspondiente,   entonces la deserialización dará como resultado una    InvalidClassException. Un serializable   la clase puede declarar su propia   serialVersionUID explícitamente por   declarando un campo llamado   "serialVersionUID" eso debe ser   estático, final y de tipo long:

ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;

Si un   clase serializable no explícitamente   declare un serialVersionUID, luego el   el tiempo de ejecución de serialización calculará un   valor predeterminado serialVersionUID para   esa clase basada en varios aspectos de   la clase, como se describe en el   Serialización de objetos Java (TM)   Especificación. Sin embargo lo és fuertemente   recomendado que todo serializable   las clases declaran explícitamente   valores de serialVersionUID, ya que   cómputo predeterminado serialVersionUID   es muy sensible a los detalles de la clase   eso puede variar dependiendo del compilador   implementaciones, y así puede resultar   en inesperado InvalidClassExceptions   durante la deserialización. Por lo tanto, para   garantizar un consistente   Valor serialVersionUID a través de   compilador de Java diferente   implementaciones, una clase serializable   debe declarar un explícito   valor serialVersionUID. Tambien es   fuertemente aconsejado que explícito   Las declaraciones serialVersionUID usan   modificador privado donde sea posible, ya que   tales declaraciones se aplican solo al   declarando inmediatamente   clase - los campos serialVersionUID no son   útil como miembros heredados.


1910
2017-11-12 23:30



Si está serializando solo porque tiene que serializar por el bien de la implementación (a quién le importa si serializa para una sesión HTTPSession, por ejemplo ... si está almacenada o no, probablemente no le importe deserializar un objeto de formulario) , entonces puedes ignorar esto.

Si realmente usa la serialización, solo importa si planea almacenar y recuperar objetos usando la serialización directamente. El serialVersionUID representa su versión de clase, y debe incrementarla si la versión actual de su clase no es retrocompatible con su versión anterior.

La mayoría de las veces, probablemente no use la serialización directamente. Si este es el caso, genere un uid serializable predeterminado haciendo clic en la opción de solución rápida y no se preocupe por ello.


415
2017-11-13 04:24



No puedo dejar pasar la oportunidad de incluir el libro de Josh Bloch Java efectivo (2da Edición). El Capítulo 11 es un recurso indispensable en la serialización de Java.

Según Josh, el UID generado automáticamente se genera en función de un nombre de clase, interfaces implementadas y todos los miembros públicos y protegidos. Cambiar cualquiera de estos de alguna manera cambiará el serialVersionUID. Por lo tanto, no es necesario que se meta con ellos solo si está seguro de que no se serializará más de una versión de la clase (ya sea a través de procesos o recuperada del almacenamiento en otro momento).

Si los ignora por el momento y descubre más tarde que necesita cambiar la clase de algún modo pero mantiene la compatibilidad con la versión anterior de la clase, puede usar la herramienta JDK serial para generar el serialVersionUID sobre el antiguo clase, y explícitamente establecer eso en la nueva clase. (Dependiendo de sus cambios, es posible que también deba implementar una serialización personalizada agregando writeObject y readObject métodos - ver Serializable javadoc o el capítulo 11 antes mencionado)


264
2017-11-12 23:37



Puedes decirle a Eclipse que ignore estas advertencias serialVersionUID:

Ventana> Preferencias> Java> Compilador> Errores / Advertencias> Posibles problemas de programación

En caso de que no lo supiera, hay muchas otras advertencias que puede habilitar en esta sección (o incluso algunas han informado como errores), muchas son muy útiles:

  • Posibles problemas de programación: Posible asignación booleana accidental
  • Posibles problemas de programación: acceso al puntero nulo
  • Código innecesario: la variable local nunca se lee
  • Código innecesario: verificación nula redundante
  • Código innecesario: cast innecesario o 'instanceof'

y muchos más.


124
2017-11-13 01:17



serialVersionUID facilita el control de versiones de datos serializados. Su valor se almacena con los datos al serializar. Al deserializar, se verifica la misma versión para ver cómo los datos serializados coinciden con el código actual.

Si desea versionar sus datos, normalmente comienza con una serialVersionUID de 0, y topar con cada cambio estructural a su clase que altera los datos serializados (agregando o eliminando campos no transitorios).

El mecanismo de deserialización incorporado (in.defaultReadObject()) se negará a deserializar las versiones anteriores de los datos. Pero si lo deseas, puedes definir tu propio readObject ()-función que puede leer datos antiguos. Este código personalizado puede verificar el serialVersionUID para saber en qué versión están los datos y decidir cómo deserializarlos. Esta técnica de control de versiones es útil si almacena datos serializados que sobreviven a varias versiones de su código.

Pero almacenar datos serializados durante un lapso de tiempo tan largo no es muy común. Es mucho más común usar el mecanismo de serialización para escribir temporalmente datos en, por ejemplo, un caché o enviarlos a otro programa con la misma versión de las partes relevantes de la base de código.

En este caso, no está interesado en mantener la compatibilidad con versiones anteriores. Solo le preocupa asegurarse de que las bases de código que se comunican tengan las mismas versiones de clases relevantes. Para facilitar dicha verificación, debe mantener el serialVersionUIDal igual que antes y no olvides actualizarlo cuando realices cambios en tus clases.

Si olvida actualizar el campo, puede terminar con dos versiones diferentes de una clase con estructura diferente pero con el mismo serialVersionUID. Si esto sucede, el mecanismo predeterminado (in.defaultReadObject()) no detectará ninguna diferencia y tratará de serializar los datos incompatibles. Ahora puede terminar con un error críptico de tiempo de ejecución o una falla silenciosa (campos nulos). Este tipo de errores puede ser difícil de encontrar.

Para ayudar a este uso, la plataforma Java le ofrece la opción de no configurar el serialVersionUID a mano. En cambio, se generará un hash de la estructura de clase en tiempo de compilación y se usará como id. Este mecanismo garantizará que nunca tenga estructuras de clase diferentes con el mismo ID, por lo que no obtendrá estas fallas de serialización de tiempo de ejecución difíciles de rastrear mencionadas anteriormente.

Pero hay una parte trasera de la estrategia de identificación generada automáticamente. A saber, los identificadores generados para la misma clase pueden diferir entre los compiladores (como lo menciona Jon Skeet arriba). Entonces, si usted comunica datos serializados entre códigos compilados con diferentes compiladores, se recomienda mantener los identificadores manualmente de todos modos.

Y si es compatible con sus datos anteriores como en el caso del primer uso mencionado, también es probable que desee mantener la identificación usted mismo. Esto con el fin de obtener identificadores legibles y tener un mayor control sobre cuándo y cómo cambian.


96
2017-10-03 06:05



Que es un serialVersionUID y por qué debería usarlo?

SerialVersionUID es un identificador único para cada clase, JVM lo usa para comparar las versiones de la clase asegurando que se usó la misma clase durante la serialización durante la deserialización.

Especificar uno le da más control, aunque JVM genera uno si no especifica. El valor generado puede diferir entre los diferentes compiladores. Además, a veces solo quieres por alguna razón prohibir la deserialización de objetos serializados viejos [backward incompatibility], y en este caso solo tiene que cambiar el serialVersionUID.

los javadocs para Serializable decir:

el cómputo serialVersionUID por defecto es altamente sensible a la clase   detalles que pueden variar según las implementaciones del compilador, y pueden   por lo tanto, resulta inesperado InvalidClassExceptions durante   deserialización.

Por lo tanto, debe declarar serialVersionUID porque nos da más control.

Este artículo tiene algunos buenos puntos sobre el tema.


62
2017-10-17 04:28



La pregunta original ha preguntado "por qué es importante" y "ejemplo" cuando este Serial Version ID sería útil. Bueno, he encontrado uno.

Digamos que creas un Car clase, instanciarlo y escribirlo en una secuencia de objetos. El objeto de automóvil aplanado se encuentra en el sistema de archivos durante un tiempo. Mientras tanto, si el Car la clase se modifica agregando un nuevo campo. Más tarde, cuando tratas de leer (es decir, deserializar), el aplanado Car objeto, obtienes el java.io.InvalidClassException - porque todas las clases serializables reciben automáticamente un identificador único. Esta excepción se produce cuando el identificador de la clase no es igual al identificador del objeto aplanado. Si realmente lo piensas, la excepción se produce debido a la adición del nuevo campo. Puede evitar que se produzca esta excepción controlando el control de versiones usted mismo al declarar un SerialVersionUID explícito. También hay un pequeño beneficio de rendimiento al declarar explícitamente su serialVersionUID(porque no tiene que ser calculado). Por lo tanto, es una buena práctica agregar su propio serialVersionUID a sus clases de Serializable tan pronto como los cree como se muestra a continuación:

public class Car {
static final long serialVersionUID = 1L; //assign a long value
}

41
2018-04-07 10:43



Si recibes esta advertencia en una clase, nunca pienses en serializar y no te declaraste implements Serializable, a menudo es porque has heredado de una superclase, que implementa Serializable. A menudo, entonces sería mejor delegar en dicho objeto en lugar de usar la herencia.

Entonces, en lugar de

public class MyExample extends ArrayList<String> {

    public MyExample() {
        super();
    }
    ...
}

hacer

public class MyExample {
    private List<String> myList;

    public MyExample() {
         this.myList = new ArrayList<String>();
    }
    ...
}

y en la llamada a métodos relevantes myList.foo() en lugar de this.foo() (o super.foo()) (Esto no se ajusta en todos los casos, pero aún bastante a menudo).

A menudo veo que las personas amplían JFrame o algo así, cuando en realidad solo necesitan delegar en esto. (Esto también ayuda a completar automáticamente en un IDE, ya que JFrame tiene cientos de métodos, que no necesita cuando quiere llamar a los personalizados en su clase).

Un caso en el que la advertencia (o el serialVersionUID) es inevitable es cuando se extiende desde AbstractAction, normalmente en una clase anónima, solo se agrega el método actionPerformed. Creo que no debería haber una advertencia en este caso (ya que normalmente no se puede serializar y deserializar de forma confiable tales clases anónimas de todas maneras en diferentes versiones de su clase), pero no estoy seguro de cómo el compilador podría reconocer esto.


33
2018-02-03 00:32



Si nunca necesitará serializar sus objetos en una matriz de bytes y enviarlos / almacenarlos, entonces no necesita preocuparse por ello. Si lo hace, entonces debe considerar su serialVersionUID ya que el deserializador del objeto lo emparejará con la versión del objeto que tiene su cargador de clases. Lea más sobre esto en la Especificación del lenguaje Java.


30
2017-11-12 23:30