In depth understanding of Java object serialization and deserialization applications

  • 2020-04-01 01:56:49
  • OfStack

When two processes are communicating remotely, they can send each other various types of data. Any type of data is sent over the network as a binary sequence. The sender needs to convert the Java object into a sequence of bytes to send over the network. The receiver needs to restore the sequence of bytes to a Java object.
The process of converting a Java object into a sequence of bytes is called serialization of the object.
The process of restoring a sequence of bytes to a Java object is called deserialization of the object.
Object serialization serves two main purposes:
1) permanently save the sequence of bytes of an object to a hard disk, usually in a file;
2) transfer the byte sequence of the object on the network.
one Serialization API in the JDK class library
Java. IO. ObjectOutputStream represents the output stream Object, its writeObject (Object obj) methods for parameter specifies the obj Object serialization, to get the sequence of bytes to a target output stream.
Java. IO. ObjectInputStream representative object input stream, its readObject () method from the source of a sequence of bytes read from the input stream, deserialize them as an object, and returns it.
Only objects of classes that implement the Serializable and Externalizable interfaces can be serialized. The Externalizable interface is inherited from the Serializable interface, the class that implements the Externalizable interface completely controls the serialization behavior by itself, and the class that only implements the Serializable interface can take the default serialization approach.
Object serialization includes the following steps:
1) create an object output stream, which can wrap a target output stream of other types, such as file output stream;
2) write objects through the writeObject() method of the object output stream.
The steps of object deserialization are as follows:
1) create an object input stream, which can wrap a source input stream of other types, such as a file input stream;
2) read the object through the readObject() method of the object input stream.
Let's take a look at a corresponding example. The contents of the class are as follows:


import java.io.*;
import java.util.Date;
public class ObjectSaver {

public static void main(String[] args) throws Exception {
 ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("D:""objectFile.obj"));
 //Serialized object
 Customer customer = new Customer(" O honey fruit ", 24);
 out.writeObject(" hello !");
 out.writeObject(new Date());
 out.writeObject(customer);
 out.writeInt(123); 
 out.close();
 // the Serialized object
 ObjectInputStream in = new ObjectInputStream(new FileInputStream("D:""objectFile.obj"));
 System.out.println("obj1=" + (String) in.readObject());
 System.out.println("obj2=" + (Date) in.readObject());
 Customer obj3 = (Customer) in.readObject();
 System.out.println("obj3=" + obj3);
 int obj4 = in.readInt();
 System.out.println("obj4=" + obj4);
 in.close();
}
}
class Customer implements Serializable {
private String name;
private int age;
public Customer(String name, int age) {
this.name = name;
this.age = age;
}
public String toString() {
return "name=" + name + ", age=" + age;
}
}

The output results are as follows:
< img Alt = "" border = 0 SRC =" / / files.jb51.net/file_images/article/201305/2013052115293053.jpg ">

two Implement the Serializable interface
ObjectOutputStream can serialize only objects of the class of the Serializable interface. By default, the ObjectOutputStream is serialized by default, which serializes only the non-transient instance variables of the object, not the transient instance variables of the object, nor the static variables.
When the ObjectOutputStream is deserialized by default, it has the following characteristics:
1) if the class to which the object belongs in memory has not been loaded, the class will be loaded and initialized first. If there is no corresponding class file in the classpath, a ClassNotFoundException is thrown;
2) no constructor of the class is called when deserialized.
If the user wants to control how the class is serialized, the following forms of writeObject() and readObject() methods can be provided in the serializable class.

private void writeObject(java.io.ObjectOutputStream out) throws IOException
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;

When an ObjectOutputStream serializes a Customer object, it executes if the object has a writeObject() method, otherwise it is serialized by default. In the object's writeObjectt() method, you can first call the defaultWriteObject() method of the ObjectOutputStream to cause the ObjectOutputStream to perform the default serialization operation. The same goes for deserialization, but this time with the defaultReadObject() method.

Some objects contain sensitive information that should not be made public. If they are serialized by default, their serialized data may be stolen when they are transferred over the network. For such information, they can be encrypted and serialized, then decrypted when deserialized, and then restored to the original information.

The default serialization method serializes the entire object graph, which requires recursive traversal of the object graph. If the object graph is complex and recursive traversal takes a lot of space and time, its internal data structure is a bidirectional list.
When applied, changing to transient type for some member variables will save space and time and improve serialization performance.
3. Implement the Externalizable interface
The Externalizable interface is inherited from the Serializable interface, and if a class implements the Externalizable interface, the class has complete control over its serialization behavior. The Externalizable interface declares two methods:

public void writeExternal(ObjectOutput out) throws IOException
public void readExternal(ObjectInput in) throws IOException , ClassNotFoundException

The former is responsible for serializing operations and the latter for deserializing operations.
When deserializing an object of a class that implements the Externalizable interface, the class's no-argument constructor is called first, as opposed to the default anti-sequence approach. If the class with no arguments constructor deleted, or access to the constructor is set to private, or protected by default level, throws Java. IO. InvalidException: no valid constructor.
Four. Serialization compatibility of different versions of serializable classes
Every class that implements the Serializable interface has a static variable that represents the serialized version identifier:

private static final long serialVersionUID;

The value of the serialVersionUID above is automatically generated by the Java runtime environment based on the internal details of the class. The value of the serialVersionUID of the newly generated class file may also change if the source code of the class is modified and recompiled.
The default value for the serialVersionUID of the class is completely dependent on the implementation of the Java compiler, and it is possible that compiling with a different Java compiler for the same class will result in a different serialVersionUID, or the same. To improve the independence and determinism of oh serialVersionUID, it is strongly recommended that the definition serialVersionUID shown in a serializable class be assigned an explicit value. Explicitly defined The serialVersionUID has two USES:
1) in some cases, different versions of the class are expected to be serializable compatible, so you need to ensure that different versions of the class have the same serialVersionUID;
2) in some cases, different versions of the class are not expected to be serializable compatible, so you need to ensure that different versions of the class have different serialversionuids


Related articles: