返回

Serializable原理:揭秘对象的存储与传输

Android

为何仅需实现Serializable接口即可完成对象序列化?

Serializable是一个Java接口,定义了一个writeExternal()和一个readExternal()方法。当对象被序列化时,writeExternal()方法将对象的状态写入一个流中,而当对象被反序列化时,readExternal()方法从流中读取对象的状态并恢复对象。实现Serializable接口的类可以被序列化,这意味着它们可以被存储在文件中或通过网络传输。

为何推荐实现一个静态final成员变量serialVersionUID?

serialVersionUID是一个long类型的变量,用于标识一个可序列化的类的版本。当一个类的结构发生变化时,它的serialVersionUID也会发生变化。如果一个可序列化的类没有定义serialVersionUID,那么Java虚拟机将自动生成一个serialVersionUID。但是,最好还是显式地定义serialVersionUID,因为这可以防止在类结构发生变化时出现兼容性问题。

序列化机制如何忽略transient和static变量?

transient关键字可以被用来修饰一个类的成员变量,表示该成员变量不参与序列化。static变量也不会被序列化。这是因为static变量属于类,而不是属于类的实例。当一个类被序列化时,只有它的实例变量才会被序列化。

示例

下面是一个示例,演示如何使用Serializable接口实现对象的序列化和反序列化:

import java.io.*;

public class Person implements Serializable {

    private String name;
    private int age;
    private transient String password;

    public Person(String name, int age, String password) {
        this.name = name;
        this.age = age;
        this.password = password;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + ", password=" + password + "]";
    }

    private static final long serialVersionUID = 1L;
}

public class Main {

    public static void main(String[] args) {
        Person person = new Person("John", 30, "secret");

        try {
            // 序列化对象
            FileOutputStream fileOutputStream = new FileOutputStream("person.ser");
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
            objectOutputStream.writeObject(person);
            objectOutputStream.close();

            // 反序列化对象
            FileInputStream fileInputStream = new FileInputStream("person.ser");
            ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
            Person deserializedPerson = (Person) objectInputStream.readObject();
            objectInputStream.close();

            // 打印反序列化后的对象
            System.out.println(deserializedPerson);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

运行上面的示例程序,您将在控制台中看到以下输出:

Person [name=John, age=30, password=null]

从输出中可以看出,password字段没有被序列化,这是因为password字段被transient关键字修饰。static变量也不参与序列化,因此serialVersionUID变量也没有被序列化。