Serializable原理:揭秘对象的存储与传输
2023-09-25 01:15:07
为何仅需实现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变量也没有被序列化。