java serialization identity

java - ¿La serialización preserva la identidad del objeto?



serialization identity (2)

Estoy utilizando la interfaz Java Serializable y ObjectOutputStream para serializar objetos (hasta ahora, este método ha sido suficiente para mis propósitos).

Mi API se basa en la identidad del objeto para algunas operaciones y me pregunto si se conservará por serialización. Es decir: si, para dos objetos arbitrarios a y b , tiene a == b antes de la serialización, ¿se mantiene después de la deserialización?

He encontrado algunos textos que afirman lo contrario , pero o bien escribieron sobre una versión anterior del JRE (solo estoy interesado en 1.6 y tal vez en 1.5), o estaban preocupados con RMI (que no es relevante para mí).

La documentation no es muy próxima a la identidad del objeto. Un artículo técnico sobre sun.com menciona que ObjectOutputStream utiliza el almacenamiento en caché de los objetos, lo que para mí solo tiene sentido si la identidad del objeto está realmente preservada, pero no tengo la confianza suficiente para confiar en esta evidencia endeble.

Lo probé (Java 1.6, OS X) y descubrí que , la identidad de los objetos no cambiaba con la serialización . ¿Pero puedo extrapolar de estos resultados o no son confiables?

Para mi prueba, he serializado el siguiente gráfico de objetos:

C----------+ | b1 b2 | +----------+ | | v v B---+ B---+ | a | | a | +---+ +---+ / / / / // A----+ | | +----+

Un código de reproducción mínimo:

import java.io.*; public class SerializeTest { static class A implements Serializable {} static class B implements Serializable { final A a; public B(A a) { this.a = a; } } static class C implements Serializable { final B b1, b2; public C() { A object = new A(); b1 = b2 = new B(object); } } public static void main(String[] args) throws IOException, ClassNotFoundException { C before = new C(); System.out.print("Before: "); System.out.println(before.b1.a == before.b2.a); // Serialization. ByteArrayOutputStream data = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(data); out.writeObject(before); out.close(); // Deserialization. ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(data.toByteArray())); C after = (C) in.readObject(); System.out.print("After: "); System.out.println(after.b1.a == after.b2.a); } }


La respuesta es no , por defecto la identidad del objeto no se preserva mediante la serialización si está considerando 2 serializaciones separadas de un objeto / gráfico dado. Por ejemplo, si un serializo un objeto sobre el cable (quizás lo envío de un cliente a un servidor a través de RMI), y luego lo hago de nuevo (en llamadas RMI separadas), entonces los 2 objetos deserializados en el servidor no serán ==.

Sin embargo, en una "serialización única", por ejemplo, un único mensaje de cliente-servidor que es un gráfico que contiene el mismo objeto varias veces, luego de la deserialización, se preserva la identidad.

Para el primer caso, puede, sin embargo, proporcionar una implementación del método readResolve para garantizar que se devuelva la instancia correcta (por ejemplo, en el patrón de ensafe tipo seguro ). readResolve es un método privado al que la JVM llamará en un objeto Java readResolve le readResolve la oportunidad de devolver una instancia diferente. Por ejemplo, así es como se puede haber implementado la enum TimeUnit enum antes de agregar las enum al lenguaje:

public class TimeUnit extends Serializable { private int id; public TimeUnit(int i) { id = i; } public static TimeUnit SECONDS = new TimeUnit(0); //Implement method and return the relevant static Instance private Object readResolve() throws ObjectStreamException { if (id == 0) return SECONDS; else return this; } }

.


Para dos objetos arbitrarios a y b, si tiene a == b antes de la serialización, seguirá siendo verdadero después de la deserialización SI:

  1. Tanto a como b se escriben y se leen posteriormente como partes de la misma secuencia. Aquí hay una cita de la documentación de ObjectInputStream : "Los gráficos de los objetos se restauran correctamente utilizando un mecanismo de intercambio de referencias ".
  2. La clase de ayb no anula readResolve() que tiene el potencial de cambiar la forma en que se restauran las referencias; tampoco las clases que tienen a y b.

Para todos los demás casos, NO se preservará la identidad del objeto.