Pregunta

Eclipse emite advertencias cuando falta un serialVersionUID .

  

La clase serializable Foo no declara un final estático   campo serialVersionUID de tipo largo

¿Qué es serialVersionUID y por qué es importante? Muestre un ejemplo donde la falta de serialVersionUID cause un problema.

¿Fue útil?

Solución

Los documentos para java.io.Serializable es probablemente una explicación tan buena como la que obtendrá:

  

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

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

Si una clase serializable no declara explícitamente un serialVersionUID , entonces el tiempo de ejecución de serialización calculará un valor predeterminado de serialVersionUID para esa clase en función de varios aspectos de la clase, como descrito en la Especificación de serialización de objetos Java (TM). Sin embargo, es muy recomendable que todas las clases serializables declaren explícitamente los valores de serialVersionUID , ya que el cálculo predeterminado de serialVersionUID es muy sensible a los detalles de la clase que pueden variar dependiendo de las implementaciones del compilador y, por lo tanto, puede dar lugar a InvalidClassExceptions inesperado durante la deserialización. Por lo tanto, para garantizar un valor consistente de serialVersionUID en diferentes implementaciones del compilador de Java, una clase serializable debe declarar un valor explícito de serialVersionUID . También se recomienda encarecidamente que las declaraciones explícitas de serialVersionUID utilicen el modificador privado siempre que sea posible, ya que dichas declaraciones se aplican solo a los campos de clase de declaración inmediata serialVersionUID no son útiles como miembros heredados.

Otros consejos

Si está serializando solo porque tiene que serializar por el bien de la implementación (a quién le importa si serializa una HTTPSession , por ejemplo ... si está almacenado o no, probablemente no lo haga ' no se preocupe por deserializar un objeto de formulario), entonces puede ignorar esto.

Si realmente está utilizando la serialización, solo importa si planea almacenar y recuperar objetos utilizando la serialización directamente. El serialVersionUID representa la versión de su clase, y debe aumentarlo si la versión actual de su clase no es compatible con su versión anterior.

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

No puedo dejar pasar esta oportunidad de conectar el libro de Josh Bloch Java efectivo (2ª 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 cualquier manera cambiará el serialVersionUID . Por lo tanto, no necesita meterse 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 un momento posterior).

Si los ignora por ahora y luego descubre que necesita cambiar la clase de alguna manera pero mantener la compatibilidad con la versión anterior de la clase, puede usar la herramienta JDK serialver para generar serialVersionUID en la clase antigua , y configúrelo explícitamente en la nueva clase. (Dependiendo de sus cambios, es posible que también necesite implementar la serialización personalizada agregando los métodos writeObject y readObject ; consulte Serializable javadoc o el capítulo 11 mencionado anteriormente).

Puede decirle a Eclipse que ignore estas advertencias de 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 tener algunas informadas como errores), muchas son muy útiles:

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

y muchos más.

serialVersionUID facilita el versionado de datos serializados. Su valor se almacena con los datos cuando se serializa. 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 un serialVersionUID de 0, y lo agrega 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 desea, puede definir su 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 período 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 través de la red 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 interesa asegurarse de que las bases de código que se comunican tienen las mismas versiones de clases relevantes. Para facilitar dicha verificación, debe mantener el serialVersionUID como antes y no olvidar actualizarlo cuando realice cambios en sus clases.

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

Entonces, para ayudar a este caso de uso, la plataforma Java le ofrece la opción de no configurar el serialVersionUID manualmente. En cambio, se generará un hash de la estructura de clases en tiempo de compilación y se usará como id. Este mecanismo se asegurará de que nunca tenga estructuras de clase diferentes con la misma identificación, por lo que no obtendrá estos fallos de serialización de tiempo de ejecución difíciles de rastrear mencionados anteriormente.

Pero hay una parte trasera de la estrategia de identificación generada automáticamente. Es decir, que los identificadores generados para la misma clase pueden diferir entre los compiladores (como se menciona anteriormente por Jon Skeet). Entonces, si comunica datos serializados entre el código compilado con diferentes compiladores, se recomienda mantener los identificadores manualmente de todos modos.

Y si usted es retrocompatible con sus datos, como en el primer caso de uso mencionado, probablemente también quiera mantener la identificación usted mismo. Esto para obtener identificadores legibles y tener un mayor control sobre cuándo y cómo cambian.

  

¿Qué 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 la misma clase se utilizó durante la serialización se carga durante la deserialización.

Especificar uno da más control, aunque JVM genera uno si no lo especifica. El valor generado puede diferir entre diferentes compiladores. Además, a veces solo desea por alguna razón prohibir la deserialización de objetos serializados antiguos [ incompatibilidad con versiones anteriores ], y en este caso solo tiene que cambiar el serialVersionUID.

Los javadocs para Serializable decir :

  

el cálculo predeterminado de serialVersionUID es altamente sensible a la clase   detalles que pueden variar según las implementaciones del compilador, y pueden   por lo tanto, se producen inesperados InvalidClassException s durante   deserialización.

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

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

La pregunta original ha preguntado 'por qué es importante' y 'ejemplo' donde este ID de versión en serie sería útil. Bueno, he encontrado uno.

Supongamos que crea una clase Car , la instancia y la escribe en una secuencia de objetos. El objeto aplanado del automóvil permanece en el sistema de archivos durante un tiempo. Mientras tanto, si la clase Car se modifica agregando un nuevo campo. Más adelante, cuando intente leer (es decir, deserializar) el objeto aplanado Car , obtendrá 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 piensa, la excepción se produce debido a la adición del nuevo campo. Puede evitar esta excepción controlando la versión usted mismo declarando un serialVersionUID explícito. También hay un pequeño beneficio de rendimiento al declarar explícitamente su serialVersionUID (porque no tiene que calcularse). Por lo tanto, es una buena práctica agregar su propio serialVersionUID a sus clases serializables tan pronto como las cree, como se muestra a continuación:

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

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

Si recibe esta advertencia en una clase que nunca piensa en serializar, y que no se declaró que implementa Serializable , a menudo es porque heredó de una superclase, que implementa Serializable A menudo, sería mejor delegar a un objeto de este tipo 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 los métodos relevantes, llame a myList.foo () en lugar de this.foo () (o super.foo () ) . (Esto no se ajusta en todos los casos, pero aún con bastante frecuencia).

A menudo veo personas que extienden JFrame o algo así, cuando realmente 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 desea llamar a sus 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 agregando 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 manera confiable tales clases anónimas de todas formas en diferentes versiones de su clase), pero no estoy seguro de cómo el compilador podría reconocer esto.

Para comprender la importancia del campo serialVersionUID, uno debe entender cómo funciona la serialización / deserialización.

Cuando un objeto de clase serializable se serializa, Java Runtime asocia un número de versión en serie (llamado serialVersionUID) con este objeto serializado. En el momento en que deserializa este objeto serializado, Java Runtime coincide con el serialVersionUID del objeto serializado con el serialVersionUID de la clase. Si ambos son iguales, entonces solo continúa con el proceso posterior de deserialización; de lo contrario, se produce InvalidClassException.

Por lo tanto, concluimos que para que el proceso de serialización / deserialización sea exitoso, el serialVersionUID del objeto serializado debe ser equivalente al serialVersionUID de la clase. En caso de que el programador especifique explícitamente el valor serialVersionUID en el programa, el mismo valor se asociará con el objeto serializado y la clase, independientemente de la plataforma de serialización y deserialización (por ejemplo, la serialización puede realizarse en una plataforma como Windows mediante el uso de sun o MS JVM y Deserialization pueden estar en diferentes plataformas Linux usando Zing JVM).

Pero en caso de que el programador no especifique serialVersionUID, al realizar Serialization \ DeSerialization de cualquier objeto, el tiempo de ejecución de Java usa su propio algoritmo para calcularlo. Este algoritmo de cálculo serialVersionUID varía de un JRE a otro. También es posible que el entorno en el que se serializa el objeto esté utilizando un JRE (por ejemplo: SUN JVM) y el entorno en el que se produce la deserialización está utilizando Linux Jvm (zing). En tales casos, serialVersionUID asociado con un objeto serializado será diferente al serialVersionUID de la clase calculada en el entorno de deserialización. A su vez, la deserialización no tendrá éxito. Entonces, para evitar tales situaciones / problemas, el programador siempre debe especificar serialVersionUID de la clase Serializable.

Primero necesito explicar la serialización.
Serialización permite convertir el objeto a transmitir, para enviar ese objeto a través de la red O Guardar en archivo O guardar en DB para uso de letras.

Hay algunas reglas para la serialización .

  • Un objeto es serializable solo si su clase o su superclase implementa la interfaz serializable

  • Un objeto es serializable (él mismo implementa la interfaz serializable) incluso si su superclase no lo es. Sin embargo, la primera superclase en la jerarquía de la clase serializable, que no implementa la interfaz serializable, DEBE tener un constructor sin argumentos. Si esto se viola, readObject () producirá una excepción java.io.InvalidClassException en tiempo de ejecución

  • Todos los tipos primitivos son serializables.

  • Los campos transitorios (con modificador transitorio) NO se serializan (es decir, no se guardan ni se restauran). Una clase que implementa Serializable debe marcar campos transitorios de clases que no admiten la serialización (por ejemplo, una secuencia de archivos).

  • Los campos estáticos (con modificador estático) no están serializados.

Cuando el objeto se serializa, JAVA Runtime asocia el número de versión de serie que se llama serialVersionID.

Donde necesitamos serialVersionID: durante la deserialización para verificar que el remitente y el receptor son compatibles con respecto a la serialización. Si el receptor carga la clase con diferente serialVersionID, la deserialización finalizará con InvalidClassCastException .
 Una clase serializable puede declarar explícitamente su propio serialVersionUID declarando un campo llamado & # 8220; serialVersionUID & # 8221; que debe ser estático, final y de tipo largo:

Probemos esto con un ejemplo.

import java.io.Serializable;    
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private String empname;
private byte empage;

public String getEmpName() {
    return name;
}
public void setEmpName(String empname) {
    this.empname = empname;
}
public byte getEmpAge() {
    return empage;
}
public void setEmpAge(byte empage) {
    this.empage = empage;
}

public String whoIsThis() {
    StringBuffer employee = new StringBuffer();
    employee.append(getEmpName()).append(" is ).append(getEmpAge()).append("
years old  "));
    return employee.toString();
}
}

Crear objeto de serialización

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class Writer {
public static void main(String[] args) throws IOException {
    Employee employee = new Employee();
    employee.setEmpName("Jagdish");
    employee.setEmpAge((byte) 30);

    FileOutputStream fout = new 
FileOutputStream("/users/Jagdish.vala/employee.obj");
    ObjectOutputStream oos = new ObjectOutputStream(fout);
    oos.writeObject(employee);
    oos.close();
    System.out.println("Process complete");
}
}

Deserializar el objeto

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class Reader {
public static void main(String[] args) throws ClassNotFoundException, 
IOException {
    Employee employee = new Employee();
    FileInputStream fin = new 
    FileInputStream("/users/Jagdish.vala/employee.obj");
    ObjectInputStream ois = new ObjectInputStream(fin);
    employee = (Employee) ois.readObject();
    ois.close();
    System.out.println(employee.whoIsThis());
 }
}    

NOTA: Ahora cambie el serialVersionUID de la clase Employee y guarde:

private static final long serialVersionUID = 4L;

Y ejecuta la clase Reader. No ejecutar la clase Writer y obtendrá la excepción.

Exception in thread "main" java.io.InvalidClassException: 
com.jagdish.vala.java.serialVersion.Employee; local class incompatible: 
stream classdesc serialVersionUID = 1, local class serialVersionUID = 4
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1623)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
at com.krishantha.sample.java.serialVersion.Reader.main(Reader.java:14)

No se moleste, el cálculo predeterminado es realmente bueno y suficiente para el 99,9999% de los casos. Y si tiene problemas, puede, como ya se ha dicho, introducir los UID a medida que llegue la necesidad (lo cual es muy poco probable)

En cuanto a un ejemplo donde el serialVersionUID faltante puede causar un problema:

Estoy trabajando en esta aplicación Java EE que se compone de un módulo web que utiliza un módulo EJB . El módulo web llama al módulo EJB de forma remota y pasa un POJO que implementa Serializable como argumento.

Esta clase POJO's fue empaquetada dentro del jar EJB y dentro de su propio jar en el WEB-INF / lib del módulo web. En realidad, son de la misma clase, pero cuando empaque el módulo EJB, desempaquete el jar de este POJO para empaquetarlo junto con el módulo EJB.

La llamada al EJB estaba fallando con la excepción a continuación porque no había declarado su serialVersionUID :

Caused by: java.io.IOException: Mismatched serialization UIDs : Source
 (Rep.
 IDRMI:com.hordine.pedra.softbudget.domain.Budget:5CF7CE11E6810A36:04A3FEBED5DA4588)
 = 04A3FEBED5DA4588 whereas Target (Rep. ID RMI:com.hordine.pedra.softbudget.domain.Budget:7AF5ED7A7CFDFF31:6227F23FA74A9A52)
 = 6227F23FA74A9A52

Generalmente uso serialVersionUID en un contexto: cuando sé que abandonará el contexto de la máquina virtual Java.

Lo sabría cuando use ObjectInputStream y ObjectOutputStream para mi aplicación o si conozco una biblioteca / marco que utilizo lo usaré. SerialVersionID garantiza que las máquinas virtuales Java diferentes de diferentes versiones o proveedores interactúen correctamente o si se almacena y recupera fuera de la máquina virtual, por ejemplo HttpSession , los datos de la sesión pueden permanecer incluso durante un reinicio y actualización de la aplicación servidor.

Para todos los demás casos, uso

@SuppressWarnings("serial")

ya que la mayoría de las veces el serialVersionUID predeterminado es suficiente. Esto incluye Excepción , HttpServlet .

Los datos de campo representan cierta información almacenada en la clase. La clase implementa la interfaz Serializable , así que eclipse se ofrece automáticamente para declarar el campo serialVersionUID . Comencemos con el valor 1 establecido allí.

Si no desea que llegue esa advertencia, use esto:

@SuppressWarnings("serial")

SerialVersionUID se utiliza para controlar la versión del objeto. También puede especificar serialVersionUID en su archivo de clase. La consecuencia de no especificar serialVersionUID es que cuando agrega o modifica cualquier campo en la clase, la clase ya serializada no podrá recuperarse porque serialVersionUID generado para la nueva clase y para el antiguo objeto serializado será diferente. El proceso de serialización de Java se basa en serialVersionUID correcto para recuperar el estado del objeto serializado y arroja java.io.InvalidClassException en caso de falta de coincidencia de serialVersionUID

Leer más: http://javarevisited.blogspot.com/ 2011/04 / top-10-java-serialization-entrevistas.html # ixzz3VQxnpOPZ

Sería bueno si CheckStyle pudiera verificar que el serialVersionUID en una clase que implementa Serializable tenga un buen valor, es decir, que coincida con lo que produciría el generador de id de versión en serie. Si tiene un proyecto con muchos DTO serializables, por ejemplo, recordar eliminar el serialVersionUID existente y regenerarlo es una molestia, y actualmente la única forma (que sé) de verificar esto es regenerar para cada clase y compararlo con el viejo. Esto es muy muy doloroso.

¿Por qué usar SerialVersionUID dentro de la clase Serializable en Java?

Durante la serialización , el tiempo de ejecución de Java crea un número de versión para una clase, de modo que pueda deserializarlo más tarde. Este número de versión se conoce como SerialVersionUID en Java.

SerialVersionUID se usa para versionar datos serializados. Solo puede des-serializar una clase si su SerialVersionUID coincide con la instancia serializada. Cuando no declaramos SerialVersionUID en nuestra clase, el tiempo de ejecución de Java lo genera para nosotros, pero no se recomienda. Se recomienda declarar SerialVersionUID como variable privada estática final larga para evitar el mecanismo predeterminado.

Cuando declara una clase como Serializable al implementar la interfaz de marcador java.io.Serializable , el tiempo de ejecución Java persiste la instancia de esa clase en el disco mediante el mecanismo de serialización predeterminado, siempre que no ha personalizado el proceso utilizando la interfaz Externalizable .

vea también ¿Por qué usar? SerialVersionUID dentro de la clase Serializable en Java

Código: javassist.SerialVersionUID

Si desea modificar una gran cantidad de clases que no tenían un serialVersionUID establecido en primer lugar, manteniendo la compatibilidad con las clases antiguas, las herramientas como IntelliJ Idea, Eclipse se quedan cortas ya que generan números aleatorios y no funcionan en un montón de archivos de una vez. Presento el siguiente script de bash (lo siento por los usuarios de Windows, considere comprar una Mac o convertir a Linux) para corregir el problema serialVersionUID con facilidad:

base_dir=$(pwd)                                                                  
src_dir=$base_dir/src/main/java                                                  
ic_api_cp=$base_dir/target/classes                                               

while read f                                                                     
do                                                                               
    clazz=${f//\//.}                                                             
    clazz=${clazz/%.java/}                                                       
    seruidstr=$(serialver -classpath $ic_api_cp $clazz | cut -d ':' -f 2 | sed -e 's/^\s\+//')
    perl -ni.bak -e "print 

Si desea modificar una gran cantidad de clases que no tenían un serialVersionUID establecido en primer lugar, manteniendo la compatibilidad con las clases antiguas, las herramientas como IntelliJ Idea, Eclipse se quedan cortas ya que generan números aleatorios y no funcionan en un montón de archivos de una vez. Presento el siguiente script de bash (lo siento por los usuarios de Windows, considere comprar una Mac o convertir a Linux) para corregir el problema serialVersionUID con facilidad:

add_serialVersionUID.sh < myJavaToAmend.lst

guarda el script, diga add_serialVersionUID.sh ~ / bin. Luego lo ejecuta en el directorio raíz de su proyecto Maven o Gradle como:

com/abc/ic/api/model/domain/item/BizOrderTransDO.java
com/abc/ic/api/model/domain/item/CardPassFeature.java
com/abc/ic/api/model/domain/item/CategoryFeature.java
com/abc/ic/api/model/domain/item/GoodsFeature.java
com/abc/ic/api/model/domain/item/ItemFeature.java
com/abc/ic/api/model/domain/item/ItemPicUrls.java
com/abc/ic/api/model/domain/item/ItemSkuDO.java
com/abc/ic/api/model/domain/serve/ServeCategoryFeature.java
com/abc/ic/api/model/domain/serve/ServeFeature.java
com/abc/ic/api/model/param/depot/DepotItemDTO.java
com/abc/ic/api/model/param/depot/DepotItemQueryDTO.java
com/abc/ic/api/model/param/depot/InDepotDTO.java
com/abc/ic/api/model/param/depot/OutDepotDTO.java

Este .lst incluye la lista de archivos java para agregar el serialVersionUID en el siguiente formato:

<*>

Este script usa la herramienta JDK serialVer bajo el capó. Así que asegúrese de que su $ JAVA_HOME / bin esté en la RUTA.

; printf qq{%s\n}, q{ private $seruidstr} if /public class/" $src_dir/$f done

guarda el script, diga add_serialVersionUID.sh ~ / bin. Luego lo ejecuta en el directorio raíz de su proyecto Maven o Gradle como:

<*>

Este .lst incluye la lista de archivos java para agregar el serialVersionUID en el siguiente formato:

<*>

Este script usa la herramienta JDK serialVer bajo el capó. Así que asegúrese de que su $ JAVA_HOME / bin esté en la RUTA.

Esta pregunta está muy bien documentada en Effective Java por Joshua Bloch. Un muy buen libro y una lectura obligada. Voy a describir algunas de las razones a continuación:

El tiempo de ejecución de serialización aparece con un número llamado Versión en serie para cada clase serializable. Este número se llama serialVersionUID. Ahora hay algo de Matemáticas detrás de este número y sale según los campos / métodos que se definen en la clase. Para la misma clase, se genera la misma versión cada vez. Este número se utiliza durante la deserialización para verificar que el emisor y el receptor de un objeto serializado hayan cargado clases para ese objeto que sean compatibles con respecto a la serialización. Si el receptor ha cargado una clase para el objeto que tiene un serialVersionUID diferente al de la clase del remitente correspondiente, la deserialización dará como resultado una InvalidClassException.

Si la clase es serializable, también puede declarar explícitamente su propio serialVersionUID declarando un campo llamado " serialVersionUID " debe ser estático, final y de tipo largo. La mayoría de los IDE como Eclipse lo ayudan a generar esa cadena larga.

Cada vez que se serializa un objeto, se marca con un número de ID de versión para la clase del objeto. Este ID se llama serialVersionUID y se calcula en función de la información sobre la estructura de clases. Suponga que creó una clase Employee y que tiene el ID de versión # 333 (asignado por JVM). Ahora, cuando serialice el objeto de esa clase (Suponga que el objeto Employee), JVM le asignará UID como # 333.

Considere una situación: en el futuro necesitará editar o cambiar su clase y, en ese caso, cuando la modifique, JVM le asignará un nuevo UID (Suponga # 444). Ahora, cuando intente deserializar el objeto de empleado, JVM comparará el ID de versión del objeto serializado (objeto de empleado) (# 333) con el de la clase, es decir, # 444 (desde que se modificó). En comparación, JVM encontrará que ambos UID de versión son diferentes y, por lo tanto, la deserialización fallará. Por lo tanto, si serialVersionID para cada clase está definido por el propio programador. Será lo mismo incluso si la clase se desarrolla en el futuro y, por lo tanto, JVM siempre encontrará que la clase es compatible con el objeto serializado aunque la clase haya cambiado. Para obtener más información, puede consultar el capítulo 14 de HEAD FIRST JAVA.

Una explicación simple:

  1. ¿Está serializando datos?

    La serialización consiste básicamente en escribir datos de clase en un archivo / secuencia / etc. La deserialización es leer esos datos nuevamente en una clase.

  2. ¿Tiene la intención de entrar en producción?

    Si solo está probando algo con datos falsos o sin importancia, no se preocupe por ello (a menos que esté probando la serialización directamente).

  3. ¿Es esta la primera versión?

    Si es así, configure serialVersionUID = 1L .

  4. ¿Es esta la segunda, tercera, etc. versión prod?

    Ahora debe preocuparse por serialVersionUID , y debe analizarlo en profundidad.

Básicamente, si no actualiza la versión correctamente cuando actualiza una clase que necesita escribir / leer, recibirá un error cuando intente leer datos antiguos.

Para contar el cuento largo, este campo se utiliza para verificar si los datos serializados se pueden deserializar correctamente. La serialización y la deserialización a menudo se realizan mediante diferentes copias del programa, por ejemplo, el servidor convierte el objeto en cadena y el cliente convierte la cadena recibida en objeto. Este campo indica que ambos operan con la misma idea sobre qué es este objeto. Este campo ayuda cuando:

  • tiene muchas copias diferentes de su programa en diferentes lugares (como 1 servidor y 100 clientes). Si cambia su objeto, modifica su número de versión y olvida actualizar uno de estos clientes, sabrá que no es capaz de deserializarlo

  • ha almacenado sus datos en algún archivo y luego intenta abrirlo con una versión actualizada de su programa con un objeto modificado; sabrá que este archivo no es compatible si mantiene su versión correcta

¿Cuándo es importante?

Más obvio: si agrega algunos campos a su objeto, las versiones anteriores no podrán usarlos porque no tienen estos campos en su estructura de objeto.

Menos obvio: cuando deserializa el objeto, los campos que no están presentes en la cadena se mantendrán como NULL. Si ha eliminado el campo de su objeto, las versiones anteriores mantendrán este campo como siempre NULL, lo que puede conducir a un mal comportamiento si las versiones anteriores dependen de datos en este campo (de todos modos, lo ha creado para algo, no solo por diversión :-))

Menos obvio: a veces cambias la idea que pones en el significado de algún campo. Por ejemplo, cuando tienes 12 años te refieres a "bicicleta". debajo de "bicicleta", pero cuando tienes 18 años te refieres a "motocicleta" - si tus amigos te invitan a "pasear en bicicleta por la ciudad" y serás el único que vino en bicicleta, entenderás lo importante que es mantener el mismo significado en todos los campos :-)

En primer lugar para responder a su pregunta, cuando no declaramos SerialVersionUID en nuestra clase, el tiempo de ejecución de Java lo genera para nosotros, pero ese proceso es sensible a muchos metadatos de clase que incluyen número de campos, tipo de campos, modificador de acceso de campos , interfaz implementada por clase, etc. Por lo tanto, se recomienda declararlo nosotros mismos y Eclipse le advierte sobre lo mismo.

Serialización: A menudo trabajamos con objetos importantes cuyo estado (datos en las variables del objeto) es tan importante que no podemos arriesgarnos a perderlo debido a fallas de alimentación / sistema (o) fallas de la red en caso de enviar el estado del objeto a otra máquina. La solución para este problema se llama "Persistencia" lo que simplemente significa persistir (mantener / guardar) los datos. La serialización es una de las muchas otras formas de lograr la persistencia (guardando datos en el disco / memoria). Al guardar el estado del objeto, es importante crear una identidad para el objeto, para poder leerlo correctamente (deserialización). Esta identificación única es ID es SerialVersionUID.

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