本文為「計算機程序的思維邏輯」系列第 62 節,系統講解 Java 標準序列化機制,涵蓋 Serializable、ObjectOutputStream/ObjectInputStream、自定義序列化、循環引用處理、版本號、Externalizable 以及與 JSON/ProtoBuf 的對比。
只需讓類實現 java.io.Serializable 標記接口,即可使用 ObjectOutputStream.writeObject() 與 ObjectInputStream.readObject() 進行對象持久化或網絡傳輸。
public class Student implements Serializable {
String name; int age; double score;
// 構造器、getter/setter...
}
// 寫入
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("students.dat"));
out.writeObject(studentList);
out.close();
// 讀取
ObjectInputStream in = new ObjectInputStream(new FileInputStream("students.dat"));
List list = (List) in.readObject();
in.close();
集合類(ArrayList、HashMap 等)與常見類(String、Date)均已實現 Serializable,可直接整體讀寫。
底層邏輯:ObjectOutputStream 維護「已寫對象表」,遇到重複對象僅寫入引用編號;ObjectInputStream 反序列化時同樣維護表,確保圖結構一致性。
當默認序列化不符合邏輯結構(如 LinkedList 的節點指針屬於實現細節)時,可採用:
transient 關鍵字:跳過該字段的默認序列化。private void writeObject(ObjectOutputStream s) 與 private void readObject(ObjectInputStream s):完全掌控讀寫流程,必須調用 s.defaultWriteObject()/s.defaultReadObject() 處理非 transient 字段及元數據。// LinkedList 示例
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject(); // 必須
s.writeInt(size);
for (Node x = first; x != null; x = x.next) s.writeObject(x.item);
}
建議顯式聲明 private static final long serialVersionUID = 1L;,避免 JVM 自動生成導致跨版本反序列化失敗(InvalidClassException)。兼容性規則:
Externalizable:完全手動控制,需實現 writeExternal/readExternal,反序列化先調無參構造器,性能優於反射機制。readResolve:單例模式反序列化保護,返回唯一實例。writeReplace:序列化代理模式,返回替代對象。| 優點 | 缺點 |
|---|---|
| 使用簡單、自動處理引用/循環、支援版本演進 | Java 私有二進制格式、體積大、反射性能低、不可跨語言 |
跨語言、高性能場景建議採用:JSON(可讀性好)、ProtoBuf/Thrift/MessagePack(二進制高效)。
