Este artículo describe la serialización y la deserialización del objeto en Java. Compártelo para todos para su referencia. Los detalles son los siguientes:
1. Introducción
La serialización del objeto se refiere al proceso de convertir un objeto en una secuencia de bytes, mientras que la deserialización es el proceso de restaurar un objeto basado en una secuencia de bytes.
La serialización se usa generalmente en los siguientes escenarios:
1. Guarde el objeto de forma permanente y guarde la secuencia de bytes del objeto al archivo local;
2. Pase los objetos en la red serializándolos;
3. Pase los objetos entre procesos a través de la serialización.
La clase a la que pertenece el objeto debe implementar la interfaz serializable o externalizable para ser serializada. Para las clases que implementan la interfaz serializable, la serialización y la deserialización adoptan el método de serialización predeterminado.
Java.io.ObjectOutputStream representa la secuencia de salida del objeto, y su método WriteObject (objeto obj) puede realizar la serialización del objeto y escribir la secuencia de byte obtenida a la secuencia de salida de destino.
Java.io.objectInputStream representa la secuencia de entrada de objeto, y su método ReadObject () puede leer una secuencia de bytes de la secuencia de entrada de origen, deserializarlo en un objeto y devolverlo.
2. Varias formas de serializar
Supongamos que se define una clase de cliente, dependiendo del método de serialización del cliente, puede haber los siguientes métodos de serialización:
1. Implementar métodos serializables e indefinidos de readobject y writeObject
ObjectOutputStream usa JDK para serializar las variables de instancia no transitoria del objeto del cliente por defecto;
ObjectInputStream deserializa las variables de instancia no transitoria del objeto del cliente utilizando el método predeterminado JDK.
2. Implementar los métodos serializables y defina ReadObject y WriteObject
ObjectOutputStream llama al método WriteObject (ObjectOutputStream Out) de la clase del cliente para serializar las variables de instancia no transitorias del objeto del cliente;
ObjectInputStream llama al método ReadObject (ObjectInputStream IN) de la clase del cliente para deserializar las variables de instancia no transitoria del objeto del cliente.
3. Implemente métodos externalizables, defina ReadExternal y WriteExternal
ObjectOutputStream llama al método WriteExternal de la clase del cliente para serializar las variables de instancia no transitoria del objeto del cliente;
ObjectInputStream primero instancia un objeto a través del constructor sin parámetros de la clase de cliente, y luego deserializa la variable de instancia no transitoria del objeto cliente utilizando el método ReadExternal.
3. Interfaz serializable
La clase permite su funcionalidad de serialización mediante la implementación de la interfaz Java.io.Serializable. Las clases que no implementan esta interfaz no podrán serializar ni deserializar ninguno de sus estados. Todos los subtipos de una clase serializable son serializables. La interfaz de serialización no tiene métodos ni campos y solo se usa para identificar la semántica serializable.
Durante el proceso de deserialización, los campos de la clase no serializada se inicializarán utilizando el constructor sin parámetros común o protegido de la clase. La subclase serializable debe poder acceder al constructor sin parámetros. Los campos que pueden ser subclases serializables se restaurarán desde la corriente.
Al atravesar una vista de clase, puede encontrar objetos que no admiten la interfaz serializable. En este caso, se lanza una NotSerializableException y se identifica la clase que no es serializable.
1. Firma precisa
Las clases que requieren un procesamiento especial durante la serialización y la deserialización deben implementar métodos especiales utilizando las siguientes firmas precisas:
Private void writeObject (java.io.objectOutputStream Out) lanza ioexception
Private void ReadObject (java.io.objectInputStream in) lanza ioexception, classNotFoundException;
privado void readObjectNodata () lanza ObjectStreamException;
El método WriteObject es responsable de escribir el estado de un objeto de una clase específica para que el método ReadObject correspondiente pueda restaurarlo. El mecanismo predeterminado para guardar los campos del objeto puede llamarse llamando. DefaultWriteObject. El método en sí no necesita involucrar a los estados pertenecientes a su superclase o subclase. El estado se puede guardar escribiendo campos individuales a ObjectOutputStream utilizando el método WriteObject o utilizando el método admitido por DataOutput para tipos de datos básicos.
El método ReadObject es responsable de leer y restaurar campos de clase de la transmisión. Puede llamar. DefaulTreadObject para llamar al mecanismo predeterminado para restaurar los campos no estatales y no transitivos del objeto. El método DeFaulTreadObject utiliza información en la transmisión para asignar campos de objetos en la secuencia que se guardan a través de los campos especificados correspondientes en el objeto actual. Esto se utiliza para tratar situaciones en las que se deben agregar nuevos campos después de la evolución de la clase. El método en sí no necesita involucrar a los estados pertenecientes a su superclase o subclase. El estado se puede guardar escribiendo campos individuales a ObjectOutputStream utilizando el método WriteObject o utilizando el método admitido por DataOutput para tipos de datos básicos.
En el caso en que el flujo de serialización no enumera la clase dada como la superclase que se deserializa, el método ReadObjectNodata es responsable de inicializar el estado del objeto de una clase específica. Esto ocurre cuando la clase de instancia deserializada utilizada por el receptor es diferente del remitente y la clase extendida por la versión del receptor no es una clase extendida por la versión del remitente. También ocurre cuando el flujo de serialización ha sido manipulado;
Al escribir objetos a una transmisión, debe especificar la clase Serializable del objeto alternativo que se utilizará, y debe implementar este método especial con una firma precisa:
Any-Access-Modifier Object WriteReSplace () lanza ObjectStreamException;
Este método de escritura se llamará por serialización, siempre que si este método existe, y se puede acceder mediante un método definido en la clase del objeto serializado. Por lo tanto, el método puede tener acceso privado, protegido y privado de paquetes. El acceso de la subclase a este método sigue las reglas de acceso Java.
Al leer una instancia de una clase de una transmisión, debe especificar la firma exacta que la clase alternativa debe usar para implementar este método especial.
Any-Access-Modifier Object ReadResolve () lanza ObjectStreamException;
Este método ReadResolve sigue las mismas reglas de llamadas y reglas de acceso que WriterePlace.
Si una clase define un método ReadResolve, entonces el método ReadResolve se llamará al final de la deserialización, y el objeto devuelto por el método es el resultado final de la deserialización.
2.serialversionUid
El tiempo de ejecución de la serialización utiliza un número de versión llamado SerialVersionUid para asociarse con cada clase serializable, que se usa durante la deserialización para verificar que el remitente y el receptor del objeto serializado cargado para el objeto. Si el receptor carga la serie SerialVersionUid de la clase del objeto diferente del número de versión del remitente correspondiente, la deserialización dará como resultado una invalidclassException. Una clase serializable puede declarar explícitamente su propia serie en serie al declarar un campo llamado "SerialSversionUid" (ese campo debe ser un campo largo y final estático):
Any-Access-Modifier estático final Long SerialVersionUid = 42L;
Si la clase Serializable no declara explícitamente SerialVersionUid, el tiempo de ejecución de la serialización calcula el valor de serie en serie predeterminado de la clase en función de varios aspectos de la clase, como se describe en la "Especificación de serialización del objeto Java (TM)". Sin embargo, se recomienda encarecidamente que todas las clases serializables declaren explícitamente los valores de la Versión en serie, porque el cálculo de la VersionUid predeterminada es altamente sensible a los detalles de la clase, y puede variar mucho dependiendo de la implementación del compilador, por lo que en el proceso de deserialización es un invalor inesperado inesperado por invaloresxceptceptionceptación inesperada. puede ser el resultado. Por lo tanto, para garantizar la consistencia entre los valores de serie en serie en diferentes compiladores de Java, la clase serializada debe declarar un valor explícito en serie VersionUid. También se recomienda utilizar el modificador privado para mostrar la declaración en serie de la declaración si es posible porque tales declaraciones solo se usan para declarar directamente la clase: el campo SerialVersionUid como miembro heredado no es útil. Las clases de matriz no pueden declarar una serie de serialsionUid explícita, por lo que siempre tienen el valor calculado predeterminado, pero las clases de matriz no coinciden con los requisitos de valor de serie SerialVersionUid.
3. Interfaz EXAPTERNABLE
Externalizable es una extensión de Serailizable.
Llame al método de la clase WriteExternal durante la serialización y deserialice el método ReadExternal;
Al realizar la deserialización, el constructor sin parámetros de la clase se llama primero, que es diferente de la deserialización predeterminada, por lo tanto, para las clases que implementan la interfaz externa para implementar la serialización, se debe proporcionar un constructor público sin parámetros.
Cuarto, resumen
Si se adopta el método de serialización predeterminado, siempre que una clase implementa la interfaz serializable, su instancia puede ser serializada. En general, las clases diseñadas específicamente para la herencia deberían tratar de no implementar la interfaz serializable, porque una vez que la clase principal implementa la interfaz serializable, todas sus subclases son serializables.
Las deficiencias del método de serialización predeterminado:
1. No es seguro serializar directamente datos confidenciales que no sean adecuados para la divulgación del objeto;
2. No verificará si las variables del miembro del objeto cumplen con las restricciones correctas y pueden ser alteradas con los datos y causar operación anormal;
3. Se requiere un recorrido recursivo del gráfico de objetos.
4. Haga la interfaz de la clase limitada por la implementación interna de la clase, restringiendo la actualización y el mantenimiento de la clase.
Implementando el tipo privado WriteObject () y ReadObject () de la interfaz serializable, o implementando la interfaz externalizable, implementando los métodos WriteExternal () y ReadExternal (), y proporcionando un constructor sin parámetros de tipo público dos formas de controlar el proceso de serialización TI TI TI puede evitar efectivamente las deficiencias del método de serialización predeterminado.
Se espera que este artículo sea útil para el diseño del programa Java de todos.