Java 的默認序列化機制會將對象的所有非靜態、非瞬態字段完整保存。雖然這提供了便利,但也帶來了問題:那些不需要持久化的數據(如緩存、臨時狀態、線程引用等)也會被一併序列化,導致數據流膨脹、性能下降,甚至引發安全隱患。
通過 transient 關鍵字標記字段,可使其不參與序列化與反序列化過程。但需注意:反序列化時,這些字段將初始化為默認值(基本類型為 0/false,引用類型為 null),開發者需自行負責恢復其合理初始值。
import java.io.*;
public class Serial implements Serializable {
int companyId;
String companyAddr;
transient boolean companyFlag; // 不參與序列化
}
反序列化本質上相當於一個「只接受數據流的 public 構造函數」,它繞過了普通構造器的初始化邏輯。若類無法通過其他途徑保證狀態一致性,必須實現 readObject 方法:先調用 defaultReadObject() 執行默認反序列化,再手動初始化 transient 字段。
默認序列化不了解業務對象結構,遇到複雜數據結構(特別是含循環引用的圖)時,會執行昂貴的「圖遍歷」來保存對象狀態。這不僅極其緩慢,還可能導致棧溢出。此時應自定義 writeObject/readObject,採用更高效的序列化策略(如扁平化存儲、引用替換等)。
Java 通過 serialVersionUID(流唯一標識符)實現版本控制。該 UID 基於類名、方法簽名等元數據隱式計算,理論上一一映射。若反序列化時發現 UID 不匹配,將拋出 InvalidClassException。
若業務明確要求舊版本數據不可讀(如遊戲回放機制),可顯式聲明新的 UID:
private static final long serialVersionUID = 1234567890L;
舊版本反序列化時將拋出異常,可捕獲並提示用戶升級。
當類結構微調(如增加非私有方法、非序列化字段)且邏輯數據未變時,應顯式指定舊版 UID 以保持兼容:
// 舊版本 UID:762508508425139227L private static final long serialVersionUID = 762508508425139227L;
實測證明:加上此聲明後,新版本類可成功反序列化舊版本數據流。
向上兼容指舊版本類能反序列化新版本生成的數據流。常見於服務端升級而客戶端滯後的場景。Java 對此提供半自動支持:新增字段若標記為 transient 或有默認值,舊版本反序列化時會忽略未知字段,保留已知字段值,從而實現平滑過渡。