El libro Effective Java y otras fuentes proporcionan una explicación bastante buena sobre cómo y cuándo usar el método readObject () cuando se trabaja con clases serializables de Java. El método readResolve (), por otro lado, sigue siendo un misterio. Básicamente, todos los documentos que encontré mencionan solo uno de los dos o mencionan ambos solo individualmente.
Las preguntas que quedan sin respuesta son:
- ¿Cuál es la diferencia entre los dos métodos?
- ¿Cuándo se debe implementar qué método?
- ¿Cómo se debe usar readResolve (), especialmente en términos de devolver qué?
Espero que puedas arrojar algo de luz sobre este asunto.
java
serialization
singleton
Forraje
fuente
fuente
String.CaseInsensitiveComparator.readResolve()
Respuestas:
readResolve
se usa para reemplazar el objeto leído de la secuencia. El único uso que he visto para esto es imponer singletons; cuando se lee un objeto, reemplácelo con la instancia singleton. Esto garantiza que nadie pueda crear otra instancia serializando y deserializando el singleton.fuente
transient
campos.readResolve
se usa para resolver el objeto después de leerlo. Un ejemplo de uso es que quizás un objeto contiene algo de caché que se puede recrear a partir de datos existentes y no necesita ser serializado; los datos almacenados en caché pueden declararsetransient
yreadResolve()
reconstruirse después de la deserialización. Para eso es para lo que sirve este método.Serializable
: dice "Las clases que necesitan designar un reemplazo cuando se lee una instancia del flujo deben implementar estereadResolve
método especial [ ] ...".Artículo 90, Java efectivo, portadas de 3.a ed
readResolve
ywriteReplace
para servidores proxy en serie: su uso principal. Los ejemplos no escribenreadObject
niwriteObject
métodos porque están utilizando la serialización predeterminada para leer y escribir campos.readResolve
se llama después de quereadObject
ha regresado (por el contrario,writeReplace
se llama anteswriteObject
y probablemente en un objeto diferente). El objeto que devuelve el método reemplaza elthis
objeto devuelto al usuarioObjectInputStream.readObject
y cualquier otra referencia posterior al objeto en la secuencia. AmbosreadResolve
ywriteReplace
pueden devolver objetos del mismo tipo o diferentes. Devolver el mismo tipo es útil en algunos casos donde los campos deben estarfinal
y se requiere compatibilidad con versiones anteriores o se deben copiar y / o validar los valores.El uso de
readResolve
no impone la propiedad singleton.fuente
readResolve se puede usar para cambiar los datos que se serializan a través del método readObject. Por ejemplo, xstream API usa esta función para inicializar algunos atributos que no estaban en el XML para ser deserializados.
http://x-stream.github.io/faq.html#Serialization
fuente
readResolve es para cuando necesite devolver un objeto existente, por ejemplo, porque está buscando entradas duplicadas que deberían fusionarse, o (por ejemplo, en sistemas distribuidos eventualmente consistentes) porque es una actualización que puede llegar antes de darse cuenta de Cualquier versión anterior.
fuente
readObject () es un método existente en la clase ObjectInputStream . Mientras lee el objeto en el momento de la deserialización, el método readObject verifica internamente si el objeto de clase que se deserializa con el método readResolve o no, si existe el método readResolve, invocará el método readResolve y devolverá el mismo ejemplo.
Por lo tanto, la intención de escribir el método readResolve es una buena práctica para lograr un patrón de diseño singleton puro en el que nadie pueda obtener otra instancia serializando / deserializando.
fuente
readResolve () asegurará el contrato singleton durante la serialización.
Por favor refiérase
fuente
Cuando se utiliza la serialización para convertir un objeto para que se pueda guardar en un archivo, podemos activar un método, readResolve (). El método es privado y se mantiene en la misma clase cuyo objeto se recupera durante la deserialización. Asegura que después de la deserialización, qué objeto se devuelve sea el mismo que se serializó. Es decir,
instanceSer.hashCode() == instanceDeSer.hashCode()
El método readResolve () no es un método estático. Después
in.readObject()
se llama durante la deserialización, solo se asegura de que el objeto devuelto sea el mismo que se serializó como se muestra a continuación mientrasout.writeObject(instanceSer)
De esta manera, también ayuda en la implementación del patrón de diseño singleton , porque cada vez que se devuelve la misma instancia.
fuente
Sé que esta pregunta es muy antigua y tiene una respuesta aceptada, pero como aparece muy alto en la búsqueda de Google, pensé en opinar porque ninguna respuesta proporcionada cubre los tres casos que considero importantes, en mi opinión, el uso principal de estos métodos. Por supuesto, todos asumen que en realidad es necesario un formato de serialización personalizado.
Tomemos, por ejemplo, clases de colección. La serialización predeterminada de una lista vinculada o un BST daría como resultado una gran pérdida de espacio con muy poca ganancia de rendimiento en comparación con solo serializar los elementos en orden. Esto es aún más cierto si una colección es una proyección o una vista: mantiene una referencia a una estructura más grande que la que expone su API pública.
Si el objeto serializado tiene campos inmutables que necesitan serialización personalizada, la solución original
writeObject/readObject
es insuficiente, ya que el objeto deserializado se crea antes de leer la parte de la secuencia escritawriteObject
. Tome esta implementación mínima de una lista vinculada:Esta estructura se puede serializar escribiendo recursivamente el
head
campo de cada enlace, seguido de unnull
valor. Sin embargo, la deserialización de un formato de este tipo se vuelve imposible:readObject
no se pueden cambiar los valores de los campos miembros (ahora fijados ennull
). Aquí viene elwriteReplace
/readResolve
par:Lo siento si el ejemplo anterior no se compila (o funciona), pero espero que sea suficiente para ilustrar mi punto. Si cree que este es un ejemplo muy descabellado, recuerde que muchos lenguajes funcionales se ejecutan en la JVM y este enfoque se vuelve esencial en su caso.
Es posible que queramos deserializar un objeto de una clase diferente de la que le escribimos
ObjectOutputStream
. Este sería el caso con vistas como unajava.util.List
implementación de lista que expone una porción de una más largaArrayList
. Obviamente, serializar toda la lista de respaldo es una mala idea y solo debemos escribir los elementos del segmento visto. Sin embargo, ¿por qué detenerse y tener un nivel inútil de indirección después de la deserialización? Simplemente podríamos leer los elementos de la secuencia en unArrayList
y devolverlo directamente en lugar de envolverlo en nuestra clase de vista.Alternativamente, tener una clase delegada similar dedicada a la serialización puede ser una opción de diseño. Un buen ejemplo sería reutilizar nuestro código de serialización. Por ejemplo, si tenemos una clase de constructor (similar al StringBuilder for String), podemos escribir un delegado de serialización que serialice cualquier colección escribiendo un generador vacío en la secuencia, seguido del tamaño de la colección y los elementos devueltos por el iterador de la colección. La deserialización implicaría leer el constructor, agregar todos los elementos leídos posteriormente y devolver el resultado final
build()
de los delegadosreadResolve
. En ese caso, tendríamos que implementar la serialización solo en la clase raíz de la jerarquía de recopilación, y no se necesitaría ningún código adicional de las implementaciones actuales o futuras, siempre que implementen resumeniterator()
ybuilder()
método (este último para recrear la colección del mismo tipo, que sería una característica muy útil en sí misma). Otro ejemplo sería tener una jerarquía de clases cuyo código no controlamos completamente: nuestras clases base de una biblioteca de terceros podrían tener cualquier número de campos privados de los que no sabemos nada y que pueden cambiar de una versión a otra, interrumpiendo Nuestros objetos serializados. En ese caso, sería más seguro escribir los datos y reconstruir el objeto manualmente en la deserialización.fuente
El método readResolve
Para las clases serializables y externalizables, el método readResolve permite que una clase reemplace / resuelva el objeto leído de la secuencia antes de que se devuelva al llamante. Al implementar el método readResolve, una clase puede controlar directamente los tipos e instancias de sus propias instancias que se deserializan. El método se define de la siguiente manera:
CUALQUIER MODIFICADOR DE ACCESO Object readResolve () lanza ObjectStreamException;
Se llama al método readResolve cuando ObjectInputStream ha leído un objeto de la secuencia y se está preparando para devolverlo al llamante. ObjectInputStream comprueba si la clase del objeto define el método readResolve. Si se define el método, se llama al método readResolve para permitir que el objeto en la secuencia designe el objeto que se devolverá. El objeto devuelto debe ser de un tipo que sea compatible con todos los usos. Si no es compatible, se lanzará una ClassCastException cuando se descubra la falta de coincidencia de tipos.
Por ejemplo, se podría crear una clase Symbol para la que solo existiera una instancia de cada enlace de símbolo dentro de una máquina virtual. El método readResolve se implementaría para determinar si ese símbolo ya estaba definido y sustituir el objeto Symbol equivalente preexistente para mantener la restricción de identidad. De esta manera, la singularidad de los objetos Symbol se puede mantener a través de la serialización.
fuente
Como ya se respondió,
readResolve
es un método privado utilizado en ObjectInputStream mientras se deserializa un objeto. Esto se llama justo antes de que se devuelva la instancia real. En el caso de Singleton, aquí podemos forzar el retorno de la referencia de instancia de singleton ya existente en lugar de la referencia de instancia deserializada. De manera similar, tenemoswriteReplace
para ObjectOutputStream.Ejemplo para
readResolve
:}
Salida:
fuente