Object serialization and deserialization in Java

  • 2020-04-01 04:08:41
  • OfStack

This article illustrates object serialization and deserialization in Java. Share with you for your reference. The details are as follows:

A list,

Object Serializable is the process of converting an object to a sequence of bytes, while deserialization is the process of restoring an object based on a sequence of bytes.

Serialization is generally used in the following scenarios:

1. Permanently save the object, and save the byte sequence of the object to the local file;
2. Passing objects in the network through serialized objects;
3. Pass objects between processes by serialization.

The class to which the object belongs must implement either the Serializable or Externalizable interfaces to be serialized. For the class that implements the Serializable interface, the serialization and deserialization adopt the default serialization mode. The Externalizable interface is an interface that inherits the Serializable interface and an extension to Serializable. The class that implements the Externalizable interface completely controls the serialization and deserialization behavior by itself.

Java. IO. ObjectOutputStream represents the output stream Object, its method writeObject (Object obj) can implement Object serialization, will get a sequence of bytes to the target output stream.

Java. IO. ObjectInputStream representative object input stream, the readObject () method to read the sequence of bytes, from the source input stream to be deserialized as the object, and returns it.

Two, several ways of serialization

Suppose a Customer class is defined. Depending on how Customer implements the serialization, there are several possible serializations:

1. Implement Serializable with undefined readObject and writeObject methods

ObjectOutputStream USES the JDK default to serialize the non-transient instance variable of the Customer object.
ObjectInputStream USES the JDK default to deserialize the non-transient instance variables of the Customer object.

2. Implement Serializable and define the readObject and writeObject methods

ObjectOutputStream calls the writeObject(ObjectOutputStream out) method of the Customer class to serialize the non-transient instance variable of the Customer object.
ObjectInputStream calls the readObject(ObjectInputStream in) method of the Customer class to deserialize the non-transient instance variable of the Customer object.

3. Implement Externalizable and define the readExternal and writeExternal methods

ObjectOutputStream calls the writeExternal method of the Customer class to serialize the non-transient instance variable of the Customer object.
ObjectInputStream first instantiates an object through the parameterless constructor of the Customer class, and then USES the readExternal method to deserialize the non-transient instance variables of the Customer object.

Iii. Serializable interface

Class enables its serialization by implementing the java.io.Serializable interface. Classes that do not implement this interface will not be able to serialize or deserialize any of their state. All subtypes of serializable classes are themselves serializable. The serialization interface has no methods or fields and is only used to identify serializable semantics.

During deserialization, the fields of the nonserializable class are initialized using the public or protected no-argument constructor of the class. Serializable subclasses must be able to access the no-argument constructor. Fields for serializable subclasses are recovered from the stream.

When traversing a class view, you may encounter objects that do not support the Serializable interface. In this case, a NotSerializableException is thrown and the class that is not serializable is identified.

Sign your name accurately

Classes that require special processing during serialization and deserialization must use the following exact signatures to implement special methods:

Private void writeObject (Java. IO. ObjectOutputStream out) throws IOException
Private void readObject (Java. IO. ObjectInputStream in) throws IOException, ClassNotFoundException.
Private void readObjectNoData() throws ObjectStreamException;

The writeObject method is responsible for writing the state of the object of a particular class so that the corresponding readObject method can restore it. The default mechanism for storing the fields of the Object can be invoked by calling out.defaultwriteobject. The method itself does not need to involve states belonging to its superclass or subclass. The state can be saved by writing each field to an ObjectOutputStream using the writeObject method or the method for the basic data type supported by DataOutput.

The readObject method is responsible for reading and recovering class fields from the stream. It can call in.defaultreadobject to invoke the default mechanism to recover non-static and non-transient fields of an object. The defaultReadObject method USES the information in the stream to allocate the fields of the objects in the stream that are saved through the corresponding specified fields in the current object. This is used to handle situations where new fields need to be added after the class has evolved. The method itself does not need to involve states belonging to its superclass or subclass. The state can be saved by writing each field to an ObjectOutputStream using the writeObject method or the method for the basic data type supported by DataOutput.

The readObjectNoData method is responsible for initializing the object state of a particular class in cases where the serialization flow does not list the given class as a superclass for the object to be deserialized. This occurs when the version of the deserialized instance class used by the receiver is different from that of the sender, and the class extended by the receiver version is not the class extended by the sender version. Occurs when the serialization stream has been tampered with; Therefore, whether the source stream is "hostile" or incomplete, the readObjectNoData method can be used to properly initialize the deserialized object.

When writing an object into the stream, you need to specify the serializable class of the alternative object to use. This special method should be implemented with an accurate signature:

Any-access-modifier Object writeReplace() throws ObjectStreamException;
This writeReplace method will be called by serialization, provided that if the method exists, it can be accessed through a method defined in the class of the serialized object. Therefore, the method can have private, protected, and package-private access. Subclasses that access this method follow Java access rules.

When reading an instance of a class from a stream, you need to specify the exact signature that the substituted class should use to implement this particular method.

Any-access-modifier Object readResolve() Object streamexception;
This readResolve method follows the same call and access rules as writeReplace.
If a class defines the readResolve method, the readResolve method is called at the end of the deserialization, and the object returned is the final result of the deserialization.

2. The serialVersionUID

The serialization runtime is associated with each serializable class with a version number called serialVersionUID, which is used during deserialization to verify that the sender and receiver of the serialized object have loaded serialization-compatible classes for the object. If the serialVersionUID of the class of the object loaded by the receiver is different from the version number of the corresponding sender's class, deserialization will result in an InvalidClassException. Serializable classes can explicitly declare their own serialVersionUID by declaring a field named "serialVersionUID" (which must be a static, final long field) :
Any-access-modifier static final long serialVersionUID = 42L;
If the serializable class does not explicitly declare the serialVersionUID, the serialization runtime calculates the default serialVersionUID value for the class based on various aspects of the class, as described in the Java(TM) object serialization specification. However, it is strongly recommended that all serializable classes explicitly declare the serialVersionUID value because calculating the default serialVersionUID is sensitive to the class's details and can vary widely depending on the compiler implementation, which can result in an unexpected InvalidClassException during deserialization. Therefore, in order for the serialVersionUID value to be consistent across different Java compiler implementations, the serialization class must declare an explicit serialVersionUID value. It is also strongly recommended that the private modifier be used to display the declaration serialVersionUID, if possible, because this declaration applies only to directly declared classes -- the serialVersionUID field is not useful as an inherited member. The array classes cannot declare an explicit serialVersionUID, so they always have a default computed value, but the array classes do not match the requirement for the serialVersionUID value.

3. The Externalizable interface

Externalizable is an extension of Serailizable. The serialization of the class that implements the Externalizable interface has the following characteristics:
The method writeExternal of the class is called when serializing, and the readExternal method is called when deserializing.
The parameterless constructor of the class is called first when deserialization is performed, which is different from the default deserialization, so for a class that implements the Externalizable interface for serialization, a public parameterless constructor must be provided, or an exception will occur when deserialization occurs.

Four,

With the default serialization, the example can be serialized simply by having a class implement the Serializable interface. In general, classes designed specifically for inheritance should try not to implement the Serializable interface, because once the parent class implements the Serializable interface, all its subclasses are Serializable as well.

Disadvantages of the default serialization:

1. It is not safe to serialize directly the sensitive data of the object that is not suitable for public disclosure;
2. Does not check whether the member variables of the object conform to the correct constraint conditions, and may be tampered with the data, resulting in abnormal operation;
3. Recursively traverse the object graph. If the object graph is very complex, it will consume a lot of resources.
4. Make the interface of the class be constrained by the internal implementation of the class, and restrict the upgrading and maintenance of the class.

The disadvantages of the default serialization approach can be effectively avoided by implementing the writeObject() and readObject() of the private type of the Serializable interface, or implementing the Externalizable interface, implementing the writeExternal() and readExternal() methods, and providing a no-argument constructor of the public type to control the serialization process.

I hope this article has been helpful to your Java programming.


Related articles: