首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Java 序列化核心:Serializable 接口原理、流程與安全陷阱

     編輯:Java 綜合教學

Java 序列化核心:Serializable 接口原理、流程與安全陷阱

Java 序列化是將對象狀態轉換為位元組流,以便持久化存儲或網絡傳輸的核心機制。本文深入剖析 Serializable 接口的工作原理、完整流程、代碼實戰及常被忽視的安全與資源風險。

一、為什麼不是所有類都需要序列化?

1. 安全風險:敏感數據(如密碼、加密金鑰、身份證號)序列化後以位元組流形式存在,極易被反序列化還原竊取,破壞數據機密性。

2. 資源耗盡風險:反序列化可無限制創建對象實例,惡意構造的序列化數據可能導致大量對象湧入堆內存,引發 OOM 攻擊。

最佳實踐:敏感字段標記 transient;實現 Externalizable 自定義加密邏輯;反序列化前驗證數據來源合法性。

二、Serializable 接口本質

java.io.Serializable 是一個**標記接口**,無任何方法。它向 JVM 聲明:「該類同意被默認序列化機制處理」。實現該接口的類,其對象即可被 ObjectOutputStream 寫出、ObjectInputStream 讀入。

三、序列化與反序列化完整流程

序列化流程

  1. 創建對象實例
  2. 包裝輸出流:FileOutputStream → ObjectOutputStream
  3. 調用 writeObject(obj) 觸發遞歸寫入對象圖
  4. 關閉流釋放資源
Person p = new Person("Alice", "123456");
File file = new File("cache.dat");
try (FileOutputStream fos = new FileOutputStream(file);
     ObjectOutputStream oos = new ObjectOutputStream(fos)) {
    oos.writeObject(p);
}

反序列化流程

  1. 包裝輸入流:FileInputStream → ObjectInputStream
  2. 調用 readObject() 讀取位元組流重建對象圖
  3. 強制類型轉換獲取目標對象
  4. 關閉流
try (FileInputStream fis = new FileInputStream(file);
     ObjectInputStream ois = new ObjectInputStream(fis)) {
    Person p = (Person) ois.readObject();
    System.out.println(p.getName() + "---" + p.getId());
}

四、序列化版本控制

JVM 使用 serialVersionUID 驗證發送端與接收端類版本一致性。

  • 顯式聲明:private static final long serialVersionUID = 1L;(強烈推薦,防止跨 JVM 部署版本不一致導致 InvalidClassException)
  • 隱式生成:未聲明時由編譯器根據類結構計算,極不穩定。

五、特殊場景處理

1. transient 關鍵字

標記字段不參與默認序列化,反序列化後該字段為默認值(null/0/false)。常用於敏感數據、非持久化緩存、計算衍生字段。

2. 自定義序列化邏輯

實現以下私有方法(非接口方法,由反射調用)完全掌控流程:

private void writeObject(ObjectOutputStream out) throws IOException {
    out.defaultWriteObject(); // 執行默認邏輯
    // 額外邏輯:加密敏感字段、寫入額外元數據
}

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
    in.defaultReadObject();
    // 額外邏輯:解密、校驗、初始化 transient 字段
}

3. Externalizable 接口

繼承 Serializable,強制實現 writeExternal/readExternal,**完全放棄默認機制**,適合高性能、加密、壓縮等深度定制場景。

六、父子類與集合序列化注意點

  • 父類實現 Serializable,子類自動可序列化;父類未實現,子類序列化時父類字段需有無參構造函數初始化。
  • 集合/數組序列化要求元素類型均實現 Serializable。
  • 靜態字段、transient 字段不參與序列化。

七、總結

Java 默認序列化雖便利,但**性能一般、跨語言差、安全風險高**。現代架構中,REST API 多採用 JSON (Jackson/Gson)、Protobuf、Avro 等高效二進制協議替代。若必須使用原生序列化,請務必:顯式聲明 serialVersionUID、敏感字段 transient、反序列化入口加驗證、考慮 Externalizable 替代。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved