1. Introduction
1.1. Definition
Serialization: Serialization is the conversion of an object to a byte stream.
Deserialization: Deserialization is the conversion of a byte stream to an object.
1.2. Use
The uses for serialization are:
Serialization can persist a sequence of bytes of an object--in memory, in a file, in a database.
A sequence of bytes that transmits an object over the network.
RMI (remote method call)
2. Serialization and deserialization
Java implements serialization and deserialization through an object input and output stream:
Serialization: The WriteObject () method for the Java.io.ObjectOutputStream class can be serialized;
Deserialization: The ReadObject () method of the Java.io.ObjectInputStream class is used to enable deserialization.
Examples of serialization and deserialization:
public class SerializeDemo01 {
Enum Sex {
MALE, FEMALE
}
Static class person implements Serializable {
Private static final long serialversionuid = 1L;
Private String name = NULL;
Private Integer age = null;
private sex sex;
Public person () {
SYSTEM.OUT.PRINTLN (call person ());
}
Public person (String name, Integer age, sex Sex) {
THIS.name = name;
This.age = age;
This.sex = sex;
}
Public String toString () {
Return Name: + THIS.name +, Age: + This.age +, sex: + This.sex;
}
}
/**
* Serialization
*/
private static void serialize (String filename) throws IOException {
File F = new file (filename); Define Save Path
OutputStream out = new FileOutputStream (f); File output stream
ObjectOutputStream oos = new ObjectOutputStream (out); Object output stream
Oos.writeobject (New Person (Jack, sex.male)); Save Object
Oos.close ();
Out.close ();
}
/**
* Deserialization
*/
private static void Deserialize (String filename) throws IOException, ClassNotFoundException {
File F = new file (filename); Define Save Path
InputStream in = new FileInputStream (f); File input stream
ObjectInputStream ois = new ObjectInputStream (in); Object input Stream
Object obj = Ois.readobject (); Reading objects
Ois.close ();
In.close ();
System.out.println (obj);
}
public static void Main (string[] args) throws IOException, ClassNotFoundException {
Final String filename = d:/text.dat;
Serialize (filename);
Deserialize (filename);
}
}
Output:
Name:jack, age:30, Sex:male
3. Serializable interface
The serialized class must belong to any of the Enum, Array, and Serializable types.
If the class is not an Enum, an Array, if serialization is required, the Java.io.Serializable interface must be implemented, otherwise the notserializableexception exception will be thrown. This is because the type is checked during the serialization operation and an exception is thrown if the serialization type requirement is not met.
We might as well make a small attempt: change the person class in the SERIALIZEDEMO01 example to the following implementation, and then look at the results of the run.
public class Unserializedemo {
Static class Person {//other content slightly}
Other content slightly
}
Output: The result is the following exception message.
Exception in thread main java.io.NotSerializableException:
...
3.1. Serialversionuid
Note that the Serialversionuid field allows you to see this field in countless classes in the Java world.
What is the role of serialversionuid and how to use Serialversionuid?
Serialversionuid is the version identity that Java produces for each serialized class. It can be used to ensure that the sender sends and receives a compatible object at the time of the deserialization. Invalidclassexception is thrown if the serialversionuid of the class received by the receiver is inconsistent with the serialversionuid sent by the sender.
If the serializable class does not explicitly declare Serialversionuid, the serialization runtime calculates the default Serialversionuid value for the class based on the various aspects of the class. In spite of this, it is recommended that you explicitly specify the value of Serialversionuid in each serialized class. Because different JDK compilations are likely to generate different serialversionuid default values, this causes the invalidclassexceptions exception to be thrown when deserializing.
The Serialversionuid field must be a static final long type.
Let's give an example:
(1) There is a serializable class of person
public class Person implements Serializable {
Private static final long serialversionuid = 1L;
private String name;
Private Integer age;
Private String address;
Construct method, get, set method slightly
}
(2) In the development process, the person has been modified to add a field email, as follows:
public class Person implements Serializable {
Private static final long serialversionuid = 1L;
private String name;
Private Integer age;
Private String address;
Private String Email;
Construct method, get, set method slightly
}
Because this class is incompatible with the old version, we need to modify the version number:
Private static final long serialversionuid = 2L;
The invalidclassexception exception is thrown when deserializing again.
In summary, we can probably be clear: Serialversionuid is used to control whether the serialized version is compatible. If we consider the modified serializable class to be backwards compatible, the SERIALVERSIONUID is not modified.
4. Default serialization mechanism
If you just let a class implement the Serializable interface without any other processing, the default serialization mechanism is used.
Using the default mechanism, when serializing an object, it not only serializes the current object itself, but also serializes the fields of its parent class and other objects referenced by that object. In the same way, other objects referenced by these other objects are serialized, and so on. Therefore, if an object contains member variables that are container class objects, and the containers contain elements that are also container class objects, the serialization process is more complex and expensive.
Note: Since the parent and reference objects here are to be serialized, they will of course satisfy the serialization requirements: The serialized class must belong to either of the Enum, Array, and Serializable types.
5. Non-default serialization mechanism
In real-world applications, the default serialization mechanism cannot be used in some cases. For example, you want to ignore sensitive data during serialization, or simplify the serialization process. Several methods that affect serialization are described below.
5.1. Transient keywords
When a field is declared as transient, the default serialization mechanism ignores the field.
We declare the age field of the inner class person in the SerializeDemo01 example as transient, as follows:
public class SerializeDemo02 {
Static class person implements Serializable {
Transient private Integer age = null;
Other content slightly
}
Other content slightly
}
Output:
Name:jack, Age:null, Sex:male
As you can see from the output, the age field is not serialized.
5.2. Externalizable interface
Either using the Transient keyword or using the writeobject () and ReadObject () methods are all based on the serialization of the Serializable interface.
Another serialization interface,--externalizable, is provided in the JDK.
After the Externalizable interface is implemented by a serializable class, the default serialization mechanism based on the Serializable interface is invalidated.
Let's make some changes based on SerializeDemo02 again, the code is as follows:
public class ExternalizeDemo01 {
Static class person implements Externalizable {
Transient private Integer age = null;
Other content slightly
private void WriteObject (ObjectOutputStream out) throws IOException {
Out.defaultwriteobject ();
Out.writeint (age);
}
private void ReadObject (ObjectInputStream in) throws IOException, ClassNotFoundException {
In.defaultreadobject ();
Age = In.readint ();
}
@Override
public void Writeexternal (ObjectOutput out) throws IOException {}
@Override
public void Readexternal (ObjectInput in) throws IOException, ClassNotFoundException {}
}
Other content slightly
}
Output:
Call Person ()
Name:null, Age:null, Sex:null
From this result, one can see that any of the fields in the person object are not serialized. On the other hand, if you are careful, you can also find that this serialization process calls the no-argument construction method of the person class.
Externalizable inherits from Serializable, which adds two methods: Writeexternal () and readexternal (). These two methods are called automatically during serialization and deserialization to perform some special operations. When the interface is used, the details of the serialization need to be done by the programmer. As shown above, the serialization behavior will not save/read any of the fields because the writeexternal () and Readexternal () methods do not do any processing. This is why the values of all the fields in the output result are empty.
In addition, if externalizable is used for serialization, when the object is read, the parameterless construction method of the serialized class is called to create a new object, and the values of the fields of the saved object are then populated into the new object. This is why the parameterless constructor method of the person class is called during this serialization. For this reason, the class implementing the Externalizable interface must provide an argument-free construction method, and its access rights are public.
Make further modifications to the person class above so that it can serialize the name and age fields, but ignore the gender field, as shown in the following code:
public class ExternalizeDemo02 {
Static class person implements Externalizable {
Transient private Integer age = null;
Other content slightly
private void WriteObject (ObjectOutputStream out) throws IOException {
Out.defaultwriteobject ();
Out.writeint (age);
}
private void ReadObject (ObjectInputStream in) throws IOException, ClassNotFoundException {
In.defaultreadobject ();
Age = In.readint ();
}
@Override
public void Writeexternal (ObjectOutput out) throws IOException {
Out.writeobject (name);
Out.writeint (age);
}
@Override
public void Readexternal (ObjectInput in) throws IOException, ClassNotFoundException {
Name = (String) in.readobject ();
Age = In.readint ();
}
}
Other content slightly
}
Output:
Call Person ()
Name:jack, age:30, Sex:null
5.3. Alternative methods for externalizable interfaces
Implementing the Externalizable interface can control the details of serialization and deserialization. It has an alternative approach: Implement the Serializable interface and add WriteObject (ObjectOutputStream out) with the ReadObject (ObjectInputStream in) method. Both methods are automatically recalled during serialization and deserialization.
Examples are shown below:
public class SerializeDemo03 {
Static class person implements Serializable {
Transient private Integer age = null;
Other content slightly
private void WriteObject (ObjectOutputStream out) throws IOException {
Out.defaultwriteobject ();
Out.writeint (age);
}
private void ReadObject (ObjectInputStream in) throws IOException, ClassNotFoundException {
In.defaultreadobject ();
Age = In.readint ();
}
Other content slightly
}
Other content slightly
}
Output:
Name:jack, age:30, Sex:male
The Defaultwriteobject () method in ObjectOutputStream is called first in the WriteObject () method, which executes the default serialization mechanism, as described in section 5.1, when the age field is ignored. The Writeint () method is then called to display the age field to the ObjectOutputStream. The function of ReadObject () is to read the object, and its principle is the same as the WriteObject () method.
Note: WriteObject () and ReadObject () are private methods, so how are they called? There is no doubt that reflection is used. Details see the Writeserialdata method in ObjectOutputStream, and the Readserialdata method in ObjectInputStream.
5.4. Readresolve () method
When we use Singleton mode, it should be expected that an instance of a class should be unique, but if the class is serializable, the situation may be slightly different. At this point, the person class used in section 2nd is modified to implement the Singleton pattern, as follows:
public class SerializeDemo04 {
Enum Sex {
MALE, FEMALE
}
Static class person implements Serializable {
Private static final long serialversionuid = 1L;
Private String name = NULL;
Transient private Integer age = null;
private sex sex;
Static final Person instatnce = new Person (Tom, sex.male);
Private person () {
SYSTEM.OUT.PRINTLN (call person ());
}
Private person (String name, Integer age, sex Sex) {
THIS.name = name;
This.age = age;
This.sex = sex;
}
public static Person getinstance () {
return instatnce;
}
private void WriteObject (ObjectOutputStream out) throws IOException {
Out.defaultwriteobject ();
Out.writeint (age);
}
private void ReadObject (ObjectInputStream in) throws IOException, ClassNotFoundException {
In.defaultreadobject ();
Age = In.readint ();
}
Public String toString () {
Return Name: + THIS.name +, Age: + This.age +, sex: + This.sex;
}
}
/**
* Serialization
*/
private static void serialize (String filename) throws IOException {
File F = new file (filename); Define Save Path
OutputStream out = new FileOutputStream (f); File output stream
ObjectOutputStream oos = new ObjectOutputStream (out); Object output stream
Oos.writeobject (New Person (Jack, sex.male)); Save Object
Oos.close ();
Out.close ();
}
/**
* Deserialization
*/
private static void Deserialize (String filename) throws IOException, ClassNotFoundException {
File F = new file (filename); Define Save Path
InputStream in = new FileInputStream (f); File input stream
ObjectInputStream ois = new ObjectInputStream (in); Object input Stream
Object obj = Ois.readobject (); Reading objects
Ois.close ();
In.close ();
System.out.println (obj);
System.out.println (obj = = person.getinstance ());
}
public static void Main (string[] args) throws IOException, ClassNotFoundException {
Final String filename = d:/text.dat;
Serialize (filename);
Deserialize (filename);
}
}
Output:
Name:jack, age:30, Sex:male
False
It is important to note that the person object obtained from the file is not equal to the singleton object in the person class. The Readresolve () method can be used in order to maintain the characteristics of the sequence in a singleton class. A singleton object that returns the person directly in the method. We add a ReadObject method based on the SerializeDemo04 example, as follows:
public class SerializeDemo05 {
Other content slightly
Static class person implements Serializable {
Add this method
private void ReadObject (ObjectInputStream in) throws IOException, ClassNotFoundException {
In.defaultreadobject ();
Age = In.readint ();
}
Other content slightly
}
Other content slightly
}
Output:
Name:jack, age:30, Sex:male
True
6. Summary
With the above content, you have already learned about the use of Java serialization. Here is a map of the brain to summarize the knowledge points.
?
Technology sharing: Java serialization