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

Java 序列化機制深度剖析:從字節格式到演算法原理

     編輯:Java 相關知識

前言

Java 序列化是將物件轉為位元組流以便網路傳輸或持久化的標準機制。雖然日常開發只需實作 Serializable,但理解其底層字節結構與演算法流程,對排查序列化相容性問題、效能優化、安全防禦至關重要。本文透過實例逐字節解析序列化輸出。

一、序列化基礎流程

// 1. 實作標記介面
class TestSerial implements Serializable {
    public byte version = 100;
    public byte count = 0;
}

// 2. 序列化寫入檔案
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("temp.out"));
oos.writeObject(new TestSerial());
oos.close();

// 3. 反序列化讀取
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("temp.out"));
TestSerial ts = (TestSerial) ois.readObject();
System.out.println(ts.version); // 100

二、字節流結構逐位解析

執行後 temp.out 內容(十六進制):

AC ED 00 05 73 72 00 0A 53 65 72 69 61 6C 54 65
73 74 A0 0C 34 00 FE B1 DD F9 02 00 02 42 00 05
63 6F 75 6E 74 42 00 07 76 65 72 73 69 6F 6E 78
70 00 64

解析對照表

位元組含義說明
AC EDSTREAM_MAGIC魔數,識別序列化協議
00 05STREAM_VERSION序列化版本
73TC_OBJECT新物件開始
72TC_CLASSDESC類描述開始
00 0A類名長度10 字元
53 65 72 69 61 6C 54 65 73 74類名"SerialTest" UTF-8
A0 0C 34 00 FE B1 DD F9serialVersionUID8 位元組,未指定則自動生成
02旗標02 = 支援序列化、非 SC_WRITE_METHOD
00 02欄位數2 個欄位
42 00 05 63 6F 75 6E 74欄位 1B=byte, 名稱 "count"
42 00 07 76 65 72 73 69 6F 6E欄位 2B=byte, 名稱 "version"
78TC_ENDBLOCKDATA類描述結束
70TC_NULL無父類
00 64實例資料version=100(0x64), count=0(0x00)

三、演算法核心步驟

  1. 寫入類中繼資料:從當前類開始,遞迴寫入父類描述,直到 java.lang.Object。
  2. 寫入實例資料:從最頂層父類開始,依序寫入各類的非 transient 實例欄位值。
  3. 物件引用處理:遇到物件引用欄位,若首次出現則寫入其類描述(TC_CLASSDESC)與資料;後續出現改寫引用句柄(TC_REFERENCE)。

四、複雜繼承與引用範例

class Parent implements Serializable { int parentVersion = 10; }
class Contain implements Serializable { int containVersion = 11; }

public class SerialTest extends Parent implements Serializable {
    int version = 66;
    Contain con = new Contain();
    // ... main 序列化
}

輸出字節流會依序包含:

  1. SerialTest 類描述(含 version、con 引用)
  2. Parent 類描述(含 parentVersion)
  3. TC_NULL 結束父類鏈
  4. Parent 實例資料 (parentVersion=10)
  5. SerialTest 實例資料 (version=66)
  6. Contain 類描述(首次遇到)
  7. Contain 實例資料 (containVersion=11)

五、關鍵注意事項

  • serialVersionUID:強烈建議顯式宣告 private static final long serialVersionUID = 1L;,避免跨 JVM 版本或編譯器差異導致反序列化失敗。
  • transient:標記欄位不參與序列化,反序列化時為預設值(null/0/false)。
  • 自定義序列化:實作 writeObject/readObject 可控制細節(如加密、壓縮、相容舊版)。
  • 安全風險:反序列化不可信資料可導致 RCE(如 Apache Commons Collections Gadget),生產環境請使用 ObjectInputFilter (Java 9+) 或第三方庫(如 NotSoSerial)防護。

總結

Java 序列化雖然自動化程度高,但其字節格式嚴格遵循規範。掌握「類描述遞迴、實例資料自頂向下、引用句柄去重」三大核心邏輯,能幫助你快速定位 InvalidClassException、StreamCorruptedException 等疑難雜症,也能在需要高效能、跨語言場景下果斷選擇 Protobuf、Avro 等替代方案。

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