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

Java 序列化機制與原理深度剖析:二進制格式、演算法流程與繼承/引用處理

     編輯:Java 相關知識

Java 序列化內部機制完整技術指南

Java 序列化將物件轉為位元組流以便持久化或網路傳輸。本文深入剖析序列化演算法、二進制格式結構、類繼承處理、物件引用共享與 serialVersionUID 關鍵機制。

序列化基礎條件

  • 實作 Serializable 標記介面 (無方法)
  • 所有非 transient 欄位需可序列化 (基本類型、String、實作 Serializable 的物件)
  • 建議顯式宣告 private static final long serialVersionUID

序列化演算法四步驟

  1. 寫入類中繼資料:類名、serialVersionUID、旗標、欄位描述
  2. 遞歸寫入父類描述:直到 java.lang.Object
  3. 從最頂層父類開始寫入實際資料值
  4. 遞歸寫入子類實例資料

二進制格式實戰解析

範例類別:

class Parent implements Serializable { int parentVersion = 10; }
class Contain implements Serializable { int containVersion = 11; }
class SerialTest extends Parent implements Serializable {
    int version = 66;
    Contain con = new Contain();
}

序列化輸出 (十六進制關鍵段落):

位元組含義說明
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
05 52 81 5A AC 66 02 F6serialVersionUID8 位元組 ID
02旗標SC_SERIALIZABLE (可序列化)
00 02欄位數2 個欄位
49 00 07 version欄位 1I=int, 長度7, "version"
4C 00 03 con 74 00 09 Lcontain;欄位 2L=object, "con", TC_STRING, JVM 簽名
78TC_ENDBLOCKDATA類描述結束
...父類 Parent 描述...
70TC_NULL無更多父類
00 00 00 42version 值66 (int)
00 00 00 0AparentVersion 值10 (int)
73 72 ...Contain 物件新物件 + 類描述 + 值 11

關鍵機制深度解析

serialVersionUID 版本控制

  • 未宣告 → JVM 依類結構自動生成 (極不穩定,增減欄位即變)
  • 顯式宣告 → 相容性由開發者控制
  • 相容變更:增欄位、增方法、改方法實作
  • 不相容變更:刪欄位、改欄位類型、改 serialVersionUID、改繼承關係

物件引用共享與循環引用

序列化使用「引用句柄」機制:

  • 首次遇到物件 → 分配句柄、寫入完整描述
  • 再次遇到同一物件 → 寫入 TC_REFERENCE + 句柄編號
  • 完美處理循環引用 (A→B→A) 與共享引用 (A→C, B→C)

特殊欄位處理

自訂序列化:writeObject/readObject

private void writeObject(ObjectOutputStream out) throws IOException {
    out.defaultWriteObject(); // 執行預設序列化
    // 額外邏輯: 加密、壓縮、寫入衍生資料
    out.writeObject(computedHash);
}

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
    in.defaultReadObject(); // 執行預設反序列化
    // 額外邏輯: 驗證、解密、重建 transient 欄位
    this.hash = (String) in.readObject();
    if (!verifyHash()) throw new InvalidObjectException("資料損毀");
}

Externalizable 完全控制

public class MyData implements Externalizable {
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeInt(version);
        out.writeUTF(name);
        // 完全手動控制
    }
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        version = in.readInt();
        name = in.readUTF();
    }
}

效能與安全考量

  • 效能:序列化較慢、產出較大;高效能場景考慮 Protobuf、Avro、Kryo
  • 安全:反序列化任意類風險 (CVE-2015-4852 等);嚴禁反序列化不可信資料、使用 ObjectInputFilter (Java 9+)
  • 版本演進:嚴格管理 serialVersionUID、提供遷移邏輯、測試向前/向後相容

理解序列化二進制格式與演算法,是排查 NotSerializableException、InvalidClassException、資料不一致等問題的關鍵。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
修飾符序列化行為
transient跳過不序列化,反序列化為預設值 (null/0/false)
static屬於類非實例,不序列化
final基本類型/String 序列化;物件引用序列化引用目標