| 類別 | 關鍵方法 | 說明 |
|---|---|---|
ObjectOutputStream | writeObject(Object) | 將物件序列化至輸出流 |
ObjectInputStream | readObject() | 從輸入流反序列化為物件 |
只有實作 Serializable 或 Externalizable 介面的類別才能被序列化。
import java.io.Serializable;
public class Person implements Serializable {
private static final long serialVersionUID = -5809782578272943999L; // 強烈建議顯式宣告
private int age;
private String name;
private String sex;
// Getter/Setter 略
}
import java.io.*;
public class SerializationDemo {
private static final String FILE = "E:/Person.ser";
public static void serialize(Person p) throws IOException {
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(FILE))) {
oos.writeObject(p);
System.out.println("序列化成功");
}
}
public static Person deserialize() throws IOException, ClassNotFoundException {
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(FILE))) {
Person p = (Person) ois.readObject();
System.out.println("反序列化成功");
return p;
}
}
public static void main(String[] args) throws Exception {
Person p = new Person();
p.setName("Gacl"); p.setAge(25); p.setSex("男");
serialize(p);
Person p2 = deserialize();
System.out.println(p2.getName() + " " + p2.getAge() + " " + p2.getSex());
}
}
反序列化時,JVM 會比較「流中的 serialVersionUID」與「當前類別的 serialVersionUID」。不一致拋出 InvalidClassException。
| 方式 | 範例 | 特點 |
|---|---|---|
預設 1L | private static final long serialVersionUID = 1L; | 簡單,但類別結構變更時需手動維護 |
| 演算法產生(預設) | private static final long serialVersionUID = 4603642343377807741L; | 基於類別簽名雜湊,結構微調即改變,極嚴格 |
// v1:已序列化到磁碟
class Customer implements Serializable {
private static final long serialVersionUID = -5182532647273106745L; // 固定版本號
private String name;
private int age;
// 建構子、toString 略
}
// v2:新增 sex 欄位,但 serialVersionUID 不變
class Customer implements Serializable {
private static final long serialVersionUID = -5182532647273106745L; // 同版本號
private String name;
private int age;
private String sex; // 新增
// 相容舊資料:反序列化時 sex 為 null,不拋異常
}
結果:舊資料可正常反序列化,新欄位預設為 null/0,達到向前兼容。
實作 private void writeObject(ObjectOutputStream) 與 private void readObject(ObjectInputStream) 可控制敏感欄位(如密碼)不序列化、或處理 transient 欄位還原。
transient 或自訂 writeObject 排除。Externalizable 或 Protobuf/Avro 等高效二進制格式。Java 序列化機制核心在於 serialVersionUID 版本協商。顯式固定版本號、理解兼容/不兼容變更規則、善用 transient 與自訂序列化,即能在分散式系統中安全、高效地傳遞物件狀態。