The interviewer was asked why Java serialization and deserialization should implement the Serializable interface

Recently, the company is doing service-oriented. It needs to implement the Serializable interface for all classes in the model package, and display the value of the specified serialVersionUID at the same time When I heard this demand, several questions suddenly appeared in my mind, such as:

(1) What are serialization and deserialization? (2) To realize serialization and deserialization, why should we implement the Serializable interface? (3) Even if the Serializable interface is implemented, why should the value of the specified serialVersionUID be displayed? (4) What value should I specify for serialVersionUID? 2021 Java interview dictionary

Let's answer these questions one by one

serialization and deserialization

Serialization: the process of converting an object into a sequence of bytes is called object serialization Deserialization: the process of restoring a byte sequence to an object is called object deserialization

When do I need serialization and deserialization?

When we only run the Java instance in the local JVM, we don't need any serialization and deserialization at this time, but when we need to persist the objects in memory to disk and database, when we need to interact with the browser, and when we need to implement RPC, we need serialization and deserialization

The first two scenarios that need serialization and deserialization make us have a big question? When we interact with the browser and persist the objects in memory into the database, we don't seem to serialize or deserialize them, because we don't implement the Serializable interface, but it works normally all the time

The following is the conclusion:

As long as we persist or network transfer the objects in memory, we need to serialize and deserialize at this time

reason:

Is it true that the Serializable interface is not used when the server interacts with the browser? JSON format actually converts an object into a String, so the data format when the server interacts with the browser is actually a String. Let's look at the source code of String type:

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

    /** Cache the hash code for the string */
    private int hash; // Default to 0

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = -6849794470754667710L;

	......
}

String type implements the Serializable interface and displays the value of the specified serialVersionUID

Then let's look at the situation when the object is persisted to the database. The insert code in the Mybatis database mapping file:

<insert id="insertUser" parameterType="org.tyshawn.bean.User">
    INSERT INTO t_user(name, age) VALUES (#{name}, #{age})
</insert>

In fact, instead of persisting the whole object to the database, we persistently persist the attributes in the object to the database, and these attributes are the basic attributes that implement the Serializable interface

To realize serialization and deserialization, why should we implement the Serializable interface?

After implementing the Serializable interface in Java, the JVM will help us realize serialization and deserialization at the bottom. If we don't implement the Serializable interface, we can write a set of serialization and deserialization code ourselves. As for the specific writing, Google will know

Even if the Serializable interface is implemented, why should the value of the specified serialVersionUID be displayed?

If the specified serialVersionUID is not displayed, the JVM will automatically generate a serialVersionUID according to the attribute during serialization, and then serialize it together with the attribute for persistence or network transmission During deserialization, the JVM will automatically generate a new version of serialVersionUID according to the attributes, and then compare the new version of serialVersionUID with the old version of serialVersionUID generated during serialization. If it is the same, the deserialization is successful, otherwise an error is reported

If the serialVersionUID is specified in the display, the JVM will still generate a serialVersionUID during serialization and deserialization, but the value is the specified value, so that the serialVersionUID of the old and new versions will be the same during deserialization

In actual development, what problems will be caused by not displaying the specified serialVersionUID? If our class is not modified after writing, there will be no problem, but this is impossible in actual development. Our class will continue to iterate. Once the class is modified, the old object deserialization will report an error Therefore, in the actual development, we will display and specify a serialVersionUID. It doesn't matter what the value is, as long as it remains unchanged

Write an example to test:

(1) User class

Do not display the specified serialVersionUID

public class User implements Serializable {

    private String name;
    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

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

(2) Test class

Serialize first and then deserialize

public class SerializableTest {

    private static void serialize(User user) throws Exception {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("D:\\111.txt")));
        oos.writeObject(user);
        oos.close();
    }

    private static User deserialize() throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("D:\\111.txt")));
        return (User) ois.readObject();
    }


    public static void main(String[] args) throws Exception {
        User user = new User();
        user.setName("tyshawn");
        user.setAge(18);
        System.out.println("Results before serialization: " + user);

        serialize(user);

        User dUser = deserialize();
        System.out.println("Result after deserialization: "+ dUser);
    }
}

(3) Results

Comment out the deserialization code, execute the serialization code, and then add a new attribute sex to the User class

public class User implements Serializable {

    private String name;
    private Integer age;
    private String sex;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

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

Comment out the serialization code and execute the deserialization code. The final result is as follows:

Results before serialization: User{name='tyshawn', age=18}
Exception in thread "main" java.io.InvalidClassException: org.tyshawn.SerializeAndDeserialize.User; local class incompatible: stream classdesc serialVersionUID = 1035612825366363028, local class serialVersionUID = -1830850955895931978

The error result is that the serialVersionUID generated by serialization and deserialization is inconsistent

Next, we specify a serialVersionUID based on the User class above

private static final long serialVersionUID = 1L;

Then perform the above steps, and the test results are as follows:

Results before serialization: User{name='tyshawn', age=18}
Result after deserialization: User{name='tyshawn', age=18, sex='null'}

After displaying the specified serialVersionUID, the problem of inconsistency between serialVersionUID generated by serialization and deserialization is solved

Other features of Java serialization

First of all, the attribute modified by the transient keyword will not be serialized, and the static attribute will not be serialized

Let's test this conclusion:

(1) User class

public class User implements Serializable {
    private static final long serialVersionUID = 1L;

    private String name;
    private Integer age;
    private transient String sex;
    private static String signature = "The world in your eyes is what you are";

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public static String getSignature() {
        return signature;
    }

    public static void setSignature(String signature) {
        User.signature = signature;
    }

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

(2) Test class

public class SerializableTest {

    private static void serialize(User user) throws Exception {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("D:\\111.txt")));
        oos.writeObject(user);
        oos.close();
    }

    private static User deserialize() throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("D:\\111.txt")));
        return (User) ois.readObject();
    }


    public static void main(String[] args) throws Exception {
        User user = new User();
        user.setName("tyshawn");
        user.setAge(18);
        user.setSex("man");
        System.out.println("Results before serialization: " + user);

        serialize(user);

        User dUser = deserialize();
        System.out.println("Result after deserialization: "+ dUser);
    }
}

(3) Results

First comment out the deserialization code and execute the serialization code, then modify the User class signature = "you are the only one in my eyes", then comment out the serialization code and execute the deserialization code. The final results are as follows:

Results before serialization: User{name='tyshawn', age=18, sex='man', signature='The world in your eyes is what you are'}
Result after deserialization: User{name='tyshawn', age=18, sex='null', signature='Only you are in my eyes'}
Copy code

Why is the static attribute not serialized? 2021 Java interview dictionary 

Because serialization is for objects, and the static attribute takes precedence over the object, it will not be serialized because it will be loaded as the class is loaded

Seeing this conclusion, does anyone ask why serialVersionUID is serialized when serialVersionUID is also modified by static?  

In fact, the serialVersionUID attribute is not serialized. When serializing objects, the JVM will automatically generate a serialVersionUID, and then assign the specified serialVersionUID attribute value to the automatically generated serialVersionUID



Posted by ex247 on Fri, 15 Apr 2022 23:50:53 +0930