2010-04-19 14 views
8

Tengo dos listas (lista1 y lista2) que contienen referencias a algunos objetos, donde algunas de las entradas de la lista pueden apuntar al mismo objeto. Luego, por varias razones, estoy serializando estas listas en dos archivos separados. Finalmente, cuando deserializo las listas, me gustaría asegurarme de que no estoy recreando más objetos de los necesarios. En otras palabras, aún debe ser posible que alguna entrada de la Lista1 apunte al mismo objeto que alguna entrada en la Lista2.Evitar objetos duplicados en la deserialización de Java

MyObject obj = new MyObject(); 
List<MyObject> list1 = new ArrayList<MyObject>(); 
List<MyObject> list2 = new ArrayList<MyObject>(); 
list1.add(obj); 
list2.add(obj); 

// serialize to file1.ser 
ObjectOutputStream oos = new ObjectOutputStream(...); 
oos.writeObject(list1); 
oos.close(); 

// serialize to file2.ser 
oos = new ObjectOutputStream(...); 
oos.writeObject(list2); 
oos.close(); 

creo que las secciones 3.4 y A.2 del spec dicen que deserialización estrictamente da lugar a la creación de nuevos objetos, pero no estoy seguro. Si es así, algunas soluciones posibles pueden implicar:

  1. Implementando equals() y hashCode() y comprobando las referencias manualmente.
  2. Creando una "clase de contenedor" para contener todo y luego serializar la clase de contenedor.

¿Hay una manera fácil de garantizar que los objetos no se duplican en la deserialización?

Gracias.

+1

No creo que esto sea posible. Para que los objetos se compartan entre las secuencias, siempre debe leer/escribir ambas secuencias juntas. Pero si debe hacer eso, ¿por qué no combinarlos en una secuencia? – finnw

Respuesta

4

Después de la deserialización de la segunda lista, puede repetir los elementos y reemplazar los duplicados por una referencia a la primera lista.

De acuerdo con 3.7 The readResolve Method, el método readResolve() no se invoca en el objeto hasta que el objeto esté completamente construido.

+0

@stacker - su segunda oración es verdadera pero no pertinente. El método 'readResolve()' no necesita devolver 'this'. –

+0

@Stephen C: la intención era mencionar que el uso de readResolve() no ayudaría a evitar la creación de instancias de objetos innecesarios. – stacker

+0

Esta será probablemente la solución menos dolorosa. – YGL

2

Puede anular el método readResolve() para reemplazar lo que se lee de la transmisión con lo que desee.

private Object readResolve() throws ObjectStreamException { 
    ... 
} 

Esto se utiliza generalmente para forzar singletons. Antes de Java 5, también se usaba para enum de tipo seguro. Nunca lo he visto usar para este escenario, pero supongo que no hay ninguna razón por la que no podría ser.

Ahora esto funcionará con los objetos individuales que controlas, pero no puedo ver cómo lo harías con un List. Podría garantizar que los objetos devueltos en esa lista no estén duplicados (según los criterios que considere).

+0

Este es el enfoque correcto. Sin embargo, el OP necesita realizar un criterio para determinar si los objetos son duplicados debe basarse en los valores de los campos de los objetos ... no en las identidades de los objetos. –

3

Creo que las secciones 3.4 y A.2 de la especificación dicen que la deserialización resulta estrictamente en la creación de nuevos objetos, pero no estoy seguro. Si es así, algunas posibles soluciones podrían incluir: ...

2, Creación de una "clase de contenedor" para sostener todo y luego la serialización de la clase de contenedor.

leí estas declaraciones como "si mi comprensión acerca de deserialización siempre creando nuevos objetos es incorrecta, entonces la solución # 2 de escribir ambas listas envueltos en una clase de contenedor a un flujo único es una solución aceptable. "

Si te entiendo correctamente, significa que crees que escribir a través de un solo contenedor que contenga ambas listas no funcionará porque aún resultará en objetos duplicados ("estrictamente como ... nuevos objetos"). Esto es incorrecto.Al escribir el gráfico de objetos (su clase contenedora), cada objeto solo se serializa una vez, independientemente de la cantidad de apariciones en el gráfico. Cuando se vuelve a leer el gráfico, ese objeto no está duplicado.

http://java.sun.com/javase/6/docs/api/java/io/ObjectOutputStream.html

El mecanismo de serialización por defecto para un objeto escribe la clase del objeto, la firma de clase, y los valores de todos los campos que no son transitorios y no estáticos. Las referencias a otros objetos (excepto en campos transitorios o estáticos) hacen que esos objetos también se escriban. Las referencias múltiples a un solo objeto se codifican utilizando un mecanismo de intercambio de referencia para que los gráficos de objetos se puedan restaurar a la misma forma que cuando se escribió el original.

Por lo tanto, si es posible, utilice la opción # 2.

Creando una "clase de contenedor" para contener todo y luego serializar la clase de contenedor.

+0

-1. Estás descuidando el hecho de que hay 2 corrientes. El mecanismo de intercambio de referencias funciona solo dentro de un solo ObjectInputStream, no entre 2 streams independientes. – finnw

+1

@finnw - Lo siento, no estoy descuidando eso. Sí, el autor de la pregunta inicialmente dijo 2 secuencias, pero luego dice, como lo mencioné anteriormente, 'Creo que ... resulta estrictamente en la creación de objetos nuevos, pero no estoy seguro'). Continúa diciendo que, si entendía mal (lo era), las 'posibles soluciones' incluyen crear un contenedor y escribir un solo flujo (' 2. Crear una 'clase de contenedor' para contener todo y luego serializar la clase contenedor .') Intentaba ser claro citando su texto anterior, pero aclararé mi respuesta para tratar de aclarar la confusión. –

+0

OK, se ha eliminado el voto a menos – finnw

Cuestiones relacionadas