當兩個進程進行遠程通訊,或需將物件持久化至磁碟時,必須將物件轉為位元組序列。序列化 = 物件 → 位元組流;反序列化 = 位元組流 → 物件。兩大用途:
ObjectOutputStream:writeObject(Object) 序列化寫入目標流ObjectInputStream:readObject() 從來源流反序列化還原物件// 序列化
ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("objectFile.obj"));
Customer c = new Customer("阿蜜果", 24);
out.writeObject("你好!");
out.writeObject(new Date());
out.writeObject(c);
out.writeInt(123); // 基本型別也支援
out.close();
// 反序列化 (順序必須一致!)
ObjectInputStream in = new ObjectInputStream(
new FileInputStream("objectFile.obj"));
System.out.println("obj1=" + (String) in.readObject());
System.out.println("obj2=" + (Date) in.readObject());
Customer c2 = (Customer) in.readObject();
System.out.println("obj3=" + c2);
System.out.println("obj4=" + in.readInt());
in.close();
obj1=你好!
obj2=Sat Sep 15 22:02:21 CST 2007
obj3=name=阿蜜果, age=24
obj4=123
transient 欄位、static 欄位ClassNotFoundException)在類中私有定義:
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject(); // 先執行預設序列化
out.writeObject(encrypt(sensitiveData)); // 再寫入加密後的敏感資料
}
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException {
in.defaultReadObject();
this.sensitiveData = decrypt((String) in.readObject());
}
transientExternalizable 完全自控介面繼承 Serializable,強制實作兩方法:
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(name);
out.writeInt(age);
// 完全由開發者決定寫什麼、怎麼寫
}
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException {
this.name = in.readUTF();
this.age = in.readInt();
}
關鍵差異:反序列化時會呼叫無參建構子,故類必須提供 public 無參建構子,否則拋 InvalidClassException。
每個可序列化類都有 private static final long serialVersionUID。JVM 預設根據類結構自動生成,修改類後重編譯可能導致 UID 變更,造成反序列化失敗 (InvalidClassException)。
public class Customer implements Serializable {
private static final long serialVersionUID = 1L; // 手動指定
// ...
}
| 策略 | 適用場景 | 做法 |
|---|---|---|
| 相容 | 新舊版本資料互通 | 維持相同 UID;新增欄位預設值、舊欄位保留 |
| 不相容 | 結構大幅變更、安全考量 | 修改 UID (如 2L);強制舊資料無法載入 |
Java 原生序列化雖方便,但不適用於異構系統整合、長期持久化、高效能場景。理解其機制、掌握版本控制、善用 transient/Externalizable,才能在必須使用時(如舊系統維護、RMI、Session 複製)游刃有餘。新專案建議採用 Jackson、Gson、Protobuf、Avro 等跨語言序列化方案。