Questions about Java serialization you really do?

introduction

When persistent data objects we rarely use Java serialization, but the use of databases and other ways to achieve. But in my opinion, Java serialization is a very important element, not only can save serialized objects to disk persistence, can also be transmitted over the network. In the usual interview them, serialized piece of content is often talked about.

When it comes to serialization, you may know that the class implements Serializable interface you can achieve the purpose of serialization, but saw the face questions about the sequence of the ignorant we often look forced.

1) What can be serialized and external interfaces interface can be the difference between that?

2) When serialized, you do not want certain members of the serialized? How to achieve?

3) What is the serialVersionUID? If you do not define a serialVersionUID, what will happen?

In fact, we are not suddenly find there are still a lot of doubts on these issues? This article will summarize some of the Java serialization of frequently asked questions and answers to pass the test and demo.

The question: What is Java serialization?

Serialize the object is to be changed can be saved to disk or sent to other processes running in binary format Java virtual machine through the network , and can restore the state of the object deserialization. Java Serialization API provides a standard mechanism for developers: by implementing the java.io.Serializable or java.io.Externalizable interfaces, ObjectInputStream and ObjectOutputStream object serialization process. Java.io.Externalizable then implement the interface, Java programmers are free to choose based on standard class structure or sequence of their self-defined binary format, which is generally considered best practice because serialized binary file format become Class part of the output of the API, the Java package may destroy the package visible and private property.

Serialization in the end what's the use?

Implement java.io.Serializable.

User-defined categories:

class User implements Serializable {
	private String username;
    private String passwd;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPasswd() {
        return passwd;
    }

    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }
}
复制代码

We object serialization, txt files stored by ObjectOutputStream, then read txt file by ObjectInputStream, anti-sequence into the User object.

public class TestSerialize {

    public static void main(String[] args) {

        User user = new User();
        user.setUsername("hengheng");
        user.setPasswd("123456");

        System.out.println("read before Serializable: ");
        System.out.println("username: " + user.getUsername());
        System.err.println("password: " + user.getPasswd());

        try {
            ObjectOutputStream os = new ObjectOutputStream(
                    new FileOutputStream("/Users/admin/Desktop/test/user.txt"));
            os.writeObject(user); // 将User对象写进文件
            os.flush();
            os.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            ObjectInputStream is = new ObjectInputStream(new FileInputStream(
                    "/Users/admin/Desktop/test/user.txt"));
            user = (User) is.readObject(); // 从流中读取User的数据
            is.close();

            System.out.println("\nread after Serializable: ");
            System.out.println("username: " + user.getUsername());
            System.err.println("password: " + user.getPasswd());

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
复制代码

Results are as follows:

序列化前数据: 
username: hengheng
password: 123456

序列化后数据: 
username: hengheng
password: 123456
复制代码

Here, we probably know what is serialized.

Second problem: serialization, you do not want certain members of the serialization, how to achieve?

Answer: The members declared as static or transient, it will not be serialized Java serialization.

  • Static variables : add the static keyword.
  • Transient variables: plus transient keyword.

Let's try to declare a variable as transient.

class User implements Serializable {
    private String username;
    private transient String passwd;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPasswd() {
        return passwd;
    }

    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }
复制代码

Before the password field plus a transient keyword run. operation result:

序列化前数据: 
username: hengheng
password: 123456

序列化后数据: 
username: hengheng
password: null
复制代码

It was found by running the password is not serialized, to reach our goal.

Try before the user name plus static keyword.

class User implements Serializable {
    private static String username;
    private transient String passwd;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPasswd() {
        return passwd;
    }

    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }
复制代码

operation result:

序列化前数据: 
username: hengheng
password: 123456

序列化后数据: 
username: hengheng
password: null
复制代码

We found that the operating results and expectations are not the same, and normally it should become null username son. What causes it?

The reason is: the value of the deserialized static class variable current JVM username value corresponding static variable, instead of the deserialized derived.

Let's prove it:

public class TestSerialize {

    public static void main(String[] args) {

        User user = new User();
        user.setUsername("hengheng");
        user.setPasswd("123456");

        System.out.println("序列化前数据: ");
        System.out.println("username: " + user.getUsername());
        System.err.println("password: " + user.getPasswd());

        try {
            ObjectOutputStream os = new ObjectOutputStream(
                    new FileOutputStream("/Users/admin/Desktop/test/user.txt"));
            os.writeObject(user); // 将User对象写进文件
            os.flush();
            os.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        User.username = "小明";
        try {
            ObjectInputStream is = new ObjectInputStream(new FileInputStream(
                    "/Users/admin/Desktop/test/user.txt"));
            user = (User) is.readObject(); // 从流中读取User的数据
            is.close();

            System.out.println("\n序列化后数据: ");
            System.out.println("username: " + user.getUsername());
            System.err.println("password: " + user.getPasswd());

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

class User implements Serializable {
    public static String username;
    private transient String passwd;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPasswd() {
        return passwd;
    }

    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }
}
复制代码

Before deserialization the value of static variables username changed to "Bob."

User.username = "小明";
复制代码

Run it again:

序列化前数据: 
username: hengheng
password: 123456

序列化后数据: 
username: 小明
password: null
复制代码

Sure enough, username here is the value of the JVM static variable, not the value obtained by deserialization.

Question three: serialVersionUID what's the use?

We often customize a serialVersionUID in class:

private static final long serialVersionUID = 8294180014912103005L
复制代码

The serialVersionUID what use is it? If not set, then what will be the consequences?

serialVersionUID is a private static final long type ID, when it is printed on the object, it is usually the object hash code. serialVersionUID can define your own, you can generate themselves.

Consequences do not specify serialVersionUID is: When you add or modify the class in any field, the serialized class will not be recovered because the old and the new class serialized object generated serialVersionUID will be different. Java serialization process is dependent on the correct sequence of objects recovery state, and triggered java.io.InvalidClassException invalid class exceptions in the case of a serialized object does not match the serial version.

For example we will understand:

We previously saved remain unchanged serialized file, and then modify the User class.

class User implements Serializable {
    public static String username;
    private transient String passwd;
    private String age;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPasswd() {
        return passwd;
    }

    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }
}
复制代码

Adding a property age, then a single writing another deserialized Method:

public static void main(String[] args) {
        try {
            ObjectInputStream is = new ObjectInputStream(new FileInputStream(
                    "/Users/admin/Desktop/test/user.txt"));
            User user = (User) is.readObject(); // 从流中读取User的数据
            is.close();

            System.out.println("\n修改User类之后的数据: ");
            System.out.println("username: " + user.getUsername());
            System.err.println("password: " + user.getPasswd());

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
复制代码

Here Insert Picture Description

Error, we found serialVersionUID after serialVersionUID and changes made before the User class generated is not the same (because it is through the object hash code generation), led InvalidClassException exception.

Custom serialVersionUID:

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

    public static String username;
    private transient String passwd;
    private String age;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPasswd() {
        return passwd;
    }

    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }
}
复制代码

Try again:

序列化前数据: 
username: hengheng
password: 123456

序列化后数据: 
username: 小明
password: null
复制代码

Operating results without error, so are generally required custom serialVersionUID.

Question 4: Can I customize the serialization process?

The answer of course is possible.

Before we introduce the second way serialization:

Externalizable interface implemented, then override the writeExternal () and readExternal () methods, which can be custom serialization.

For example, we try to put variable to transients.

public class ExternalizableTest implements Externalizable {

    private transient String content = "我是被transient修饰的变量哦";

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(content);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException,
            ClassNotFoundException {
        content = (String) in.readObject();
    }

    public static void main(String[] args) throws Exception {

        ExternalizableTest et = new ExternalizableTest();
        ObjectOutput out = new ObjectOutputStream(new FileOutputStream(
                new File("test")));
        out.writeObject(et);

        ObjectInput in = new ObjectInputStream(new FileInputStream(new File(
                "test")));
        et = (ExternalizableTest) in.readObject();
        System.out.println(et.content);

        out.close();
        in.close();
    }
}
复制代码

operation result:

我是被transient修饰的变量哦
复制代码

Implemented here is Externalizable interface, there can be no automatic serialization, you need to manually specify the variables to be serialized in writeExternal method, regardless of whether the transient modification.

Through this introduction, are not we have more understanding of the Java serialization?

Author: Yang Hyong

Source: CreditEase Institute of Technology

Guess you like

Origin juejin.im/post/5e671a07f265da574727a0d8