2011-10-03 12 views
8

Esta pregunta ha sido objeto de algunas animadas discusiones en mi equipo. Mi elección personal es utilizar¿Cuáles son los pros y los contras de usar serialVersionUID y @SuppressWarnings ("serie") en las clases que implementan Serializable?

@SuppressWarnings("serial") 

Mis pensamientos son que significa que hay una cosa menos para mantener comparación con el uso

serialVersionUID 

Estoy en lo correcto al pensar que el uso de este permite que el compilador para generar el UID y, por lo tanto, es más probable que capte cambios en la clase.

Mi mayor temor es que depender de un desarrollador para cambiar el UID cuando cambian la clase es más probable que conduzca a errores imprevistos.

¿Hay algún inconveniente en mi enfoque? ¿Alguien más ha tenido buenas o malas experiencias usando cualquiera de estos enfoques?

+0

¿Esta clase está destinada a la serialización, o simplemente implementa Serializable (por ejemplo, ampliando alguna clase serializable)? –

+0

@Eran Supongamos que está destinado a la serialización. –

+0

¿Cómo suprimir una advertencia hace que las cosas * sean mejores *? ¿Has comprobado el código de bytes para ver si el compilador inserta un UID? –

Respuesta

5

Todo se reduce a esta pregunta:

  • se leerán y escrito por el mismo código solo o por código diferente los flujos con número de serie?

"código diferente" puede significar varias cosas:

  • versiones antiguas frente a las nuevas versiones
  • dos programas independientes con tal viejas y nuevas bibliotecas
  • más de cosas por el estilo.

En estos casos se debe firmemente adherirse a los contratos de serialización - y esto no sólo la creación realizados por serialVersionUId - por lo general también debe sobrescribir los métodos para la serialización y deserialización de hacer frente a diferentes versiones.

Si, por otro lado, el mismo programa lee y escribe cosas para algo así como un caché interno y ese caché se puede reconstruir desde cero cuando se actualiza el software, entonces siéntase libre de hacer su vida tan fácil como usted puede.

Entre estos extremos hay, por supuesto, varios tonos de gris.

3

Al serializar un Objeto, si tiene un identificador de serie, se utilizará; de lo contrario, se generará.

Si falta el identificador de serie y se especifica la opción javac-Xlint, se generará una advertencia. Esta advertencia se puede silenciar con @SuppressWarnings("serial"). El propósito de esta anotación es simplemente suprimir la advertencia, no interferirá de ninguna otra manera con la serialización.

De Serializable Javadoc:

la serialización asociados de tiempo de ejecución con cada clase serializable un número de versión, llamada serialVersionUID, que se utiliza durante la deserialización para verificar que el emisor y el receptor de un objeto serializado han cargado clases para ese objeto que son compatibles con respecto a la serialización.

y también:

Si una clase serializable no declara explícitamente un serialVersionUID, entonces el tiempo de ejecución de serialización calculará un valor serialVersionUID predeterminado para esa clase en base a varios aspectos de la clase, como descrito en la especificación de serialización de objetos Java (TM). Sin embargo, se recomienda encarecidamente que todas las clases serializables declaren explícitamente los valores de serialVersionUID, ya que el cómputo serialVersionUID predeterminado es muy sensible a los detalles de clase que pueden variar dependiendo de las implementaciones del compilador y puede dar lugar a InvalidClassExceptions inesperados durante la deserialización.

Ejemplo: serialising una clase con @SuppressWarnings("serial")

Test.java: la clase se va a serializar

import java.io.Serializable; 

@SuppressWarnings("serial") 
class Test implements Serializable { 
    int a = 0; 
    public Test() { 
    } 
    public Test(int arg) { 
     a = arg; 
    } 
} 

Writer.java: la clase que escribe un caso de prueba para la prueba de archivos. serie

import java.io.*; 

class Writer { 
    public static void main(String[] args) { 
     Test t = new Test(2); 
     String filename = "test.serial"; 
     try { 
      FileOutputStream fos = new FileOutputStream(filename); 
      ObjectOutputStream out = new ObjectOutputStream(fos); 
      out.writeObject(t); 
      out.close(); 
     } catch (IOException ex) { 
      ex.printStackTrace(); 
     } 
    } 
} 
+0

Pequeño comentario: no es que '@ SuppressWarnings' provoque el' serialVersionUID' ser generado. Se genera de todos modos, siempre que no esté configurado en el archivo. –

+0

@SeanOwen, reformulé la oración. gracias – stivlo

4

Como de costumbre, la respuesta definitiva está en su propio capítulo de Effective Java.

TL; DR. El uso de @SuppressWarnings("serial") está bien (y es bueno para eliminar la advertencia) a menos que realmente desee serializar la clase. En ese caso, desea implementar realmente serialVersionUID, y hacerlo correctamente, regenerarlo (o al menos cambiarlo) después de cada cambio en la clase que podría causar problemas en la deserialización.

1

Si cree que deberá agregar algo a esta clase en el futuro, continúe y codifique serialVersionUID en 1L si ya no tiene objetos serializados. Si ya tiene objetos serializados y necesita permanecer compatible con ellos, use la herramienta serialver para descubrir a qué se ha configurado Java y usar ese valor.

De esta manera podrá agregar atributos a esta clase en el futuro y podrá mantenerse automáticamente compatible. Si no hace lo anterior, esto no se manejará automáticamente y deberá escribir el código para convertir las clases anteriores a las nuevas cada vez que agregue un campo a la clase.

+0

Creo que existe un posible peligro en este enfoque, suponiendo que todos los cambios futuros sean compatibles con la serialización. ¿Qué sucede si la versión 2 agrega un campo String? puede ser válido leer objetos viejos sin este campo y su valor predeterminado es nulo, pero ¿está seguro? Todavía requiere cuidado, ¡tanto como mantener en realidad 'serialVersionUID'! –

+0

De acuerdo. Con cada cambio a la clase esto debe ser pensado. –

2

No utilizar serialVersionUID es el enfoque conservador. Cualquier cambio en el formato serializado se considerará un cambio incompatible. Significa que puede encontrar errores al deserializar objetos escritos por una versión anterior, que podría tener sentido para deserializar, si hubiera escrito código de deserialización personalizado y usado serialVersionUID.

Su uso tiene la ventaja de la posibilidad de preservar la compatibilidad a través de más versiones del objeto serializado, pero introduce un nuevo tipo de fallo potencial: si se olvida de actualizar serialVersionUID después de cambiar una clase de una manera incompatible, el mejor Lo que puede ocurrir es que también se obtiene un error en el tiempo de ejecución porque los datos no se pueden leer con sensatez. Pero, puede tener éxito silenciosamente, tal vez ignorando o malinterpretando datos serializados en el proceso.

Entonces, primero decida cuál quiere: úselo o no?Definitivamente prefiero no usar serialVersionUID a menos que sea claramente necesario, y existe el compromiso de mantenerlo correctamente.

Si no lo usa, puede desactivar las advertencias con @SuppressWarnings, pero también puede desactivarlo globalmente en javac con -Xlint:-serial. Ese es un enfoque aproximado, conveniente quizás, pero asegúrese de que realmente quiera hacer eso. Es apropiado si, por ejemplo, definitivamente no usa serialVersionUID en ninguna parte.

0

Tengo que decir que su elección de SuppressWarning es mala. Debería definir explícitamente serialVersionUID. Mantenerlo no es tanto trabajo mientras te salvará la vida en el futuro.

En algún momento en el futuro, si desea cambiar la definición de la clase (inevitable si su trabajo es serio) mientras logra la compatibilidad con versiones anteriores, serialVersionUID le salvará la vida. Si no lo define, Java calculará serialVersionUID basado en la firma de clase (?); simplemente reordenar las variables cambiaría la firma y rompería la compatibilidad (o incluso agregaría una función de ayuda). En serio, definir serialVersionUID le salvará la vida.

Debe leer la sección Serialización en Java efectivo como lo sugirieron otras personas.

Cuestiones relacionadas