2008-09-03 17 views
7

En Java, los campos estáticos y transitorios no se serializan. Sin embargo, descubrí que la inicialización de campos estáticos causa que el serialVersionUID generado se cambie. Por ejemplo, static int MYINT = 3; hace que el serialVersionUID cambie. En este ejemplo, tiene sentido porque diferentes versiones de la clase obtendrían valores iniciales diferentes. ¿Por qué cualquier inicialización cambia el serialVersionUID? Por ejemplo, static String MYSTRING = System.getProperty("foo"); también hace que el serialVersionUID cambie.serialización de Java con inicialización estática

Para ser específico, mi pregunta es por qué la inicialización con un método hace que el serialVersionUID cambie. El problema que golpeé es que agregué un nuevo campo estático que se inicializó con un valor de propiedad del sistema (getProperty). Ese cambio causó una excepción de serialización en una llamada remota.

Respuesta

5

Puede encontrar información sobre esto en el bug 4365406 y en el algorithm for computing serialVersionUID. Básicamente, al cambiar la inicialización de su miembro static con System.getProperty(), el compilador introduce una nueva propiedad static en su clase que hace referencia a la clase System (supongo que la clase System no se refirió previamente en su clase), y desde esta propiedad introducida por el compilador no es privado, participa en el cálculo serialVersionUID.

Moralidad: utilizar siempre explícita serialVersionUID, se ahorrará algunos ciclos de CPU y algunos dolores de cabeza :)

0

Si leo las especificaciones correctamente, el serialVersionUID automático no debería cambiar si cambia el valor de un campo estático transitorio. Eche un vistazo a Chapter 5.6 de la especificación.

Sin embargo, si se piensa en esto un poco - se empieza por la serialización de un objeto que tiene static int MYINT = 3, cuando, a continuación deserializar la clase que espera obtener el mismo objeto hacia atrás, es decir, con MYINT = 3. Por lo tanto, si cambia la inicialización estática, esperaría que el serialVersionUID cambie porque no puede volver a obtener el mismo objeto.

De todas formas, tenga esto en todas sus clases serializables y se puede controlar el serialVersionUID:

private static final long serialVersionUID = 7526472295622776147L; 
0

He actualizado la cuestión de ser más clara. Entiendo por qué la inicialización con un literal cambia el serialVersionUID pero no por qué la inicialización dinámica lo cambia. Si se inicializa con un método, el valor, por supuesto, siempre puede ser diferente.

Establecer el serialVersionUID explícitamente está bien en una versión posterior de la clase solo si está seguro de que se trata de un cambio seguro.

2

automática serialVersionUID se calcula sobre la base de los miembros de una clase. Se pueden mostrar para un archivo de clase con la herramienta javap en Sun JDK.

En el caso mencionado en la pregunta, el miembro que se agrega/elimina es el inicializador estático. Esto aparece como() V en archivos de clase. El contenido del método se puede desmontar usando javap -c. Debería poder distinguir la llamada y asignación de System.getProperty ("foo") a MYSTRING. Sin embargo, una asignación con un literal de cadena (o cualquier constante de tiempo de compilación según lo definido por la especificación de lenguaje Java) es soportada directamente por el archivo de clase, por lo que se elimina la necesidad de un inicializador estático.

Un caso común para la segmentación de código J2SE 1.4 (use -source 1.4 -target 1.4) o anterior es campos estáticos para instancias de clase antiguas que aparecen como literales de clase en el código fuente (MyClass.class). La instancia de Clase se busca a demanda con Class.forName y la almacenada en un campo estático. Es este campo estático el que interrumpe el serialVersionUID. Desde J2SE 5.0, una variante del código de operación ldc brinda soporte directo para literales de clase, eliminando la necesidad del campo sintético. De nuevo, todo esto se puede mostrar con javap -c.

Cuestiones relacionadas