usar serializacion serial que porque objeto intellij generate deserializacion calculate java generics instance-initializers

java - serializacion - Entendiendo esta advertencia: La clase serializable no declara un serialVersionUID final estático



serializacion y deserializacion en java (6)

Generalmente estoy de acuerdo con Bart K., pero con fines informativos:
La advertencia también puede eliminarse agregando el campo, que puede generarse automáticamente presionando ctrl + 1.
La advertencia también se puede suprimir agregando la anotación @SuppressWarnings ("serial") antes de la definición.
La clase anónima implementa Serializeable, y Serializeable requiere este campo estático para que las versiones puedan distinguirse al serializar y deserializar. Más información aquí:
http://www.javablogging.com/what-is-serialversionuid/

Tengo un código inicializador estático:

someMethodThatTakesAHashMap(new HashMap<K, V>() { { put("a","value-a"); put("c","value-c");} });

Por alguna razón recibo una advertencia de Eclipse: La clase serializable no declara un serialVersionUID final estático.

¿Se queja esto de la clase anónima? ¿Qué puedo hacer al respecto o simplemente debería suprimirlo?


La clase ImmutableMap de la biblioteca de colecciones de Google es útil para esta situación. p.ej

someMethodThatTakesAHashMap(ImmutableMap.<K, V>builder().put("a","value-a").put("c","value-c").build());

o

someMethodThatTakesAHashMap(ImmutableMap.of("a","value-a","c","value-c"));


La sintaxis que está utilizando se llama inicialización de doble refuerzo , que en realidad es un " bloque de inicialización de instancia que forma parte de una clase interna anónima " (ciertamente no es un hack). Entonces, al usar esta notación, en realidad estás definiendo una nueva clase (!).

El "problema" en su caso es que HashMap implementa Serializable . Esta interfaz no tiene ningún método y sirve solo para identificar la semántica de ser serializable . En otras palabras, es una interfaz de marcador y concretamente no tiene que implementar nada. Pero , durante la deserialización, Java usa un número de versión llamado serialVersionUID para verificar que la versión serializada sea compatible con el objetivo. Si no proporciona este serialVersionUID , se calculará. Y, tal como se documenta en el javadoc de Serializable , el valor calculado es extremadamente sensible y, por lo tanto, se recomienda declararlo explícitamente para evitar cualquier problema de deserialización. Y esto es de lo que Eclipse se está "quejando" (tenga en cuenta que esto es solo una advertencia).

Por lo tanto, para evitar esta advertencia, podría agregar un serialVersionUID a su clase interna anónima:

someMethodThatTakesAHashMap(new HashMap<String, String>() { private static final long serialVersionUID = -1113582265865921787L; { put("a", "value-a"); put("c", "value-c"); } });

Pero pierde la concisión de la sintaxis (y es posible que ni siquiera la necesite).

Por lo tanto, otra opción sería ignorar la advertencia agregando @SuppressWarnings("serial") al método en el que está llamando a someMethodThatTakesAHashMap(Map) . Esto parece más apropiado en su caso.

Dicho todo esto, aunque esta sintaxis es concisa, tiene algunos inconvenientes. Primero, si mantiene una referencia en el objeto inicializado usando una inicialización de doble refuerzo, implícitamente mantendrá una referencia al objeto externo que no será elegible para la recolección de basura. Así que ten cuidado. En segundo lugar (aunque suena como una micro optimización), la inicialización de doble refuerzo tiene un poco de sobrecarga . Tercero, esta técnica en realidad usa clases internas anónimas como hemos visto y, por lo tanto, consume un poco de espacio permanente (pero dudo que esto sea realmente un problema a menos que realmente abuses de ellas). Finalmente, y este es quizás el punto más importante, no estoy seguro de que haga que el código sea más legible (no es una sintaxis muy conocida).

Entonces, aunque me gusta usarlo en las pruebas (para la concisión), tiendo a evitar usarlo en el código "regular".


Para abordar la otra mitad de su pregunta, "¿debo suprimirla?" -

Sí. En mi opinión, esta es una advertencia terrible. serialVersionUID no debe usarse por defecto, no al revés.

Si no agrega serialVersionUID, lo peor que sucede es que dos versiones de un objeto que son compatibles con la serialización se consideran incompatibles. serialVersionUID es una manera de declarar que la compatibilidad de serialización no ha cambiado, anulando la evaluación predeterminada de Java.

Al usar serialVersionUID, lo peor que sucede es que inadvertidamente no actualiza el ID cuando la forma serializada de la clase cambia de una manera incompatible. En el mejor de los casos, también obtiene un error de tiempo de ejecución. En el peor de los casos, algo peor sucede. E imagina lo fácil que es no actualizarlo.


Sí, podrías suprimir la advertencia, pero la reescribiría así:

HashMap<String, String> map = new HashMap<String, String>(); map.put("a","value-a"); map.put("c","value-c"); someMethodThatTakesAHashMap(map);

No se necesita supresión, y mucho mejor para leer, IMO.


Su intención era inicializar una instancia anónima de HashMap. La advertencia es una pista de que tu código está haciendo más de lo que pretendías.

Lo que buscamos es una forma de inicializar una instancia de HashMap anónima. Lo que tenemos arriba crea una subclase anónima de HashMap y luego crea una instancia anónima de esa clase anónima.

Debido a que el código hace más de lo que estaba previsto, lo llamaría un hack.

Lo que realmente queremos es algo como esto:

foo(new HashMap<String, String>({"a", "value-a"}, {"c", "value-c"}));

Pero desgraciadamente esto no es Java válido. No hay una manera de hacer esto de una manera segura para el tipo utilizando una matriz de pares clave / valor. Java simple no tiene el poder expresivo.

El método ImmutableMap.of estático de la Colección Google está cerca, pero significa crear una versión del método de fábrica para varios números de pares clave / valor. (Ver la respuesta de Finnw.)

Así que mantén las cosas simples. Vaya con la solución de Bart K a menos que su código esté lleno de esta inicialización. Si es así use ImmutableMap. O bien, cree su propia subclase de HashMap con los métodos de "estilo" de fábrica. O cree estos métodos de fábrica de estilo "of" en una clase de utilidad. Aquí hay uno para dos pares clave / valor:

public final MapUtil { public static <K,V> Map<K,V> makeMap(K k1, V v1, K k2, V v2) { Map<K,V> m = new HashMap<K,V>(); m.put(k1, v1); m.put(k2, v2); return m; } }

Abrace la verbosidad y relájese sabiendo que sus compañeros de trabajo corporativos están usando las mismas cadenas que usted.