Java foundation — serialization

Time:2020-11-5

1. Why serialization?

From Java programming ideas

When the object is created, it can be obtained during the running of the program, but when the program is terminated, all the objects will be cleared, and we can’t get any more. Of course, you can do this by writing information to a file or database. But for the sake of convenience, Java provides us with serialization mechanism and hides most details. ——Bruce Eckel

Java provides serialization:

  • Java Remote method call RMI.
  • The use of Java beans.

2. What is serialization?

Using java object serialization, when saving an object, its state will be saved as a set of bytes, and these bytes will be assembled into objects in the future.It must be noted that object serialization preserves the “state” of an object, that is, its member variables. As you can see, object serialization does not focus on static variables in the class.Java foundation -- serialization

3. How to serialize?

2.1 serialization mechanism 1: serializable interfaceJava foundation -- serialization

Serializable interface is the simplest way to realize serialization. If a class implements serializable interface, it can indicate that the object of this class can be serialized! Otherwise, an error will be reported.The common default implementation of this interface is the encapsulation type of all basic types, string, container class and even class object!

//You can see that there is nothing inside the serializable interface in the source code, just an identifier!
public interface Serializable {
    //nothing!
}

Serialization and deserialization methods: calling objectoutputstream and objectinputstream Java foundation -- serialization

package ddx.serialize;

import java.io.*;

public class Main {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Person person = new Person(18,"ddx");
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("person.out") );
        out.writeObject("person storage\n");
        out.writeObject(person);
        out.close();
        System.out.print("Serialization"+"person storage\n"+ person);

        ObjectInputStream in  = new ObjectInputStream(new FileInputStream("person.out"));
        String title = (String)in.readObject(); //Note that the deserialization order is consistent with the serialization order
        Person person1 = (Person) in.readObject();
        in.close();
        System.out.print(Deserialize+title+ person1);
    }
}
class Person implements Serializable{
    public int age;
    public String name;
    Person(int age , String s){
        this.age = age;
        this.name = s;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

Operation results

Serializing person storagePerson{age=18, name='ddx'}Deserialize person storagePerson{age=18, name='ddx'}

output file

Java foundation -- serialization

Note: again, the body of object serialization is member variables, not static variablesJava foundation -- serializationJava foundation -- serializationJava foundation -- serializationOne class is serialized, the other is deserialized and executed separately!
ackage ddx.serialize;

import java.io.*;

public class Main {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Person person = new Person(18,"ddx");
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("person.out") );
        out.writeObject("person storage\n");
        out.writeObject(person);
        out.close();
        System.out.println("Serialization"+"person storage\n"+ person);
    }
}
class Person implements Serializable{
    public int age;
    public String name;
    public static int count = 0;
    Person(int age , String s){
        this.age = age;
        this.name = s;
        count++;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ",count='"+count+'\'' +
                '}';
    }
}
package ddx.serialize;

import java.io.*;

public class test {
    public static void main(String[] args) throws IOException, ClassNotFoundException {

        ObjectInputStream in = new ObjectInputStream(new FileInputStream("person.out"));
        String title = (String) in.readObject();
        Person person1 = (Person) in.readObject();
        in.close();
        System.out.println(Deserialize + title + person1);
    }
}
Serializing person storagePerson{age=18, name='ddx',count='1'}Deserialize person storagePerson{age=18, name='ddx',count='0'}

//Through the above output, we can see that serialization does not do any operation on static variables, only retains the initial value!!!!

2.2 serializable serialization rules

Using the default mechanism, when you serialize an object, you will not only serialize the current object itself, but also other objects referenced by the object. Similarly, other objects referenced by these other objects will also be serialized, and so on. This situation is calledObject networkTherefore, if the member variables contained in an object are container class objects, and the elements contained in these containers are also container class objects, the serialization process will be more complex and costly.

2.3 external interface

Externalizable inherits from serializable. When using this interface, the details of serialization need to be completed by the programmer.

In addition to the above manual completion, the differences between the two also include the following points:Java foundation -- serialization

  • When you use the object deserialization of serializable interface to recover an object, it is constructed entirely by storing its binary bits
  • When the object is deserialized to recover the object with externalizable interface, there must be at least one default public constructor!!!! Then call the readExternal method!
public interface Externalizable extends java.io.Serializable {
    void writeExternal(ObjectOutput out) throws IOException;
    void readExternal(ObjectInput in) throws IOException,ClassNotFoundException;
}

Demo code:

package ddx.serialize;

import java.io.*;

public class Main1 {
    public static void main(String[] args ) throws IOException, ClassNotFoundException {
        info info1 = new info(10,"ddx");
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("info.out"));
        out.writeObject(info1);
        System.out.println(Before serialization+info1);
        out.close();

        ObjectInputStream in = new ObjectInputStream(new FileInputStream("info.out"));
        info info2 = (info) in.readObject();
        System.out.println(After serialization+info2);
    }
}
class info implements Externalizable{
    public int id;
    public String name;
    public info(int id, String name){
        this.id = id;
        this.name = name;
        System.out.println("Info executing constructor with parameters");
    }

    public info(){
        System.out.println("Info executing parameterless constructor");
    }
    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeInt(this.id);
        out.writeObject(name);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        //1
        //in.readInt();
        //in.readObject();
        id = in.readInt();
        name = (String)in.readObject();
    }

    @Override
    public String toString() {
        return "info{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

2.4 transient keyword

Use the transient keyword to select fields that do not need to be serialized. For example, some sensitive private information, you can choose to use the keyword, virtual opportunity to ignore this field!!!Java foundation -- serialization

package ddx.serialize;

import java.io.*;

public class Main2 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Message  message = new Message(201792237,533534);
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("Self_Message.out"));
        out.writeObject(message);
        out.close();
        System.out.println(Before serialization + message);

        ObjectInputStream  in = new ObjectInputStream(new FileInputStream("Self_Message.out"));
        Message message1 = (Message) in.readObject();
        System.out.println("After serialization" + message1);
    }
}
class Message implements Serializable {
    private int id;
    private transient int password; //Transient keyword modification!!!
    Message(int id, int password){
        this.id = id;
        this.password = password;
    }

    @Override
    public String toString() {
        return "message{" +
                "id=" + id +
                ", password=" + password +
                '}';
    }
}
Message before serialization{id=201792237, password=533534}Message after serialization{id=201792237, password=0}

As we can see from the output,If the transient decorated property is used, this field will be ignored in Java serialization. Therefore, the property modified by transient is the default value for the deserialized object. For the reference type, the value is null; for the base type, the value is 0; for the boolean type, the value is false.Java foundation -- serializationJava foundation -- serializationJava foundation -- serialization

2.5 serialization persistence

If the same object is serialized multiple times, will this object be serialized multiple times?The answer isnegativeYes.

package ddx.serialize;

import java.io.*;

public class Main3 {

    public static void main(String[] args) throws Exception {
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("teacher.txt"))) {
            Person person = new Person(20,Luffy);
            Teacher t1 = new Teacher("Raleigh", person);
            Teacher t2 = new Teacher("Red hair shanks", person);
            //Write four objects in turn to the input stream
            oos.writeObject(person);
            oos.writeObject(t1);
            oos.writeObject(t2);
            oos.writeObject(t2);//Repeated serialization of the same object!!!!!!

            oos.close();

            ObjectInputStream in = new ObjectInputStream(new FileInputStream("teacher.txt"));
            Person p = (Person) in.readObject();
            Teacher tt1 = (Teacher)in.readObject();
            Teacher tt2 = (Teacher)in.readObject();
            Teacher tt3 = (Teacher)in.readObject();
            System.out.println(p);
            System.out.println(tt1);
            System.out.println(tt2);
            System.out.println(tt3);
        }
    }

}
class Teacher implements Serializable{
    public  String name;
    public Person person;
    Teacher(String name, Person person){
        this.name = name;
        this.person = person;
    }

    @Override
    public String toString() {
        return "Teacher{" +super.toString()+
                "name='" + name + '\'' +
                ", person=" + person +
                '}';
    }
}
Initializing.serialize.Person@6f496d9f
Teacher{ddx.serialize.Teacher@723279cf  name='Raleigh', person=ddx.serialize.Person@6f496d9f}
Teacher{ddx.serialize.Teacher@10f87f48  name='Red hair shanks', person=ddx.serialize.Person@6f496d9f}
Teacher{ddx.serialize.Teacher@10f87f48  name='Red hair shanks', person=ddx.serialize.Person@6f496d9f}
//It can be found that person has not been serialized many times, and T2 has only been serialized once!!! The address is the same!

As can be seen from the output results,Java serializes the same object and does not serialize the object multiple times to get multiple objects.Java foundation -- serialization

Java serialization algorithm

  1. All objects saved to disk have a serialization code number
  2. When the program attempts to serialize an object, it first checks whether the object has been serialized. Only if the object has never been serialized (in this virtual machine), it will serialize the object as a byte sequence output.
  3. If the object has been serialized, the number can be output directly.

Shows the above serialization process (different order! The principle is consistent)

Java foundation -- serialization

4. Version control

We know that,Deserialization must have a class file, but with the upgrade of the project, the class file will also be upgraded. How can serialization ensure the compatibility before and after the upgrade?

Java serialization provides a serialization version number of private static final long serialVersionUID. Only the version number is the same. Even if the serialization property is changed, the object can be deserialized back correctly.

public class Person implements Serializable {
    //Serialization version number
    private static final long serialVersionUID = 1111013L;
    private String name;
    private int age;
    //Ellipsis construction method and get, set
}

If theThe version number of the classAnd serializationatypism, deserialization willInvalid classexception is reported.

Java foundation -- serialization

The serialization version number can be freely specified. If not specified, the JVM will calculate a version number according to the class information, so that it can’t be deserialized correctly with the upgrade of the class. Another obvious hidden danger of not specifying the version number is that it is not conducive to the migration between JVMs. Maybe the class file has not been changed, but the calculation rules of different JVMs may be different, which will lead to the failure of deserialization 。

When do you need to modify the serialversion uid? There are three casesJava foundation -- serializationJava foundation -- serializationJava foundation -- serialization

  • If only the method is modified and the deserialization is not affected, there is no need to modify the version number;
  • If only static variables and transient variables are modified, the deserialization is not affected and the version number does not need to be modified;
  • If a non transient variable is modified, deserialization may fail. If the type of instance variable in the new class is inconsistent with the type of the class in serialization, deserialization will fail. In this case, the serialVersionUID needs to be changed. If only instance variables are added, the new ones are the default values after deserialization; if instance variables are reduced, the reduced instance variables will be ignored during deserialization.

5. SummaryJava foundation -- serialization Java foundation -- serializationJava foundation -- serialization

  1. All objects that need network transmission need to implement serializable interface. It is suggested that all JavaBeans implement serializable interface.
  2. The class name and instance variables (including basic types, arrays, and references to other objects) of an object will be serialized; methods, class variables, and transient instance variables will not be serialized.
  3. If you want a variable not to be serialized, use the transient modifier.
  4. The reference type member variable of the serialized object must also be serializable, otherwise, an error will be reported.
  5. When deserializing, there must be a class file for the serialized object.
  6. When the serialized object is read through the file or network, it must be read in the order in which it is actually written.
  7. To serialize singleton classes, the readresolve() method needs to be overridden; otherwise, the singleton principle will be broken.
  8. The same object is serialized multiple times. Only the first time is serialized as a binary stream. Later, the serialization number is only saved, and the serialization will not be repeated.
  9. It is recommended that all serializable classes be added with serialVersionUID version number to facilitate project upgrade.

This work adoptsCC agreementThe author and the link to this article must be indicated in the reprint