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

Java transient 關鍵字深度解析:序列化排除與預設值陷阱

     編輯:Java 相關知識

transient 是 Java 序列化機制的「隱形開關」,標記欄位不參與序列化。但許多開發者只知其一、不知其二——反序列化時建構子不執行、預設值失效、靜態欄位天然排除等細節。本文透過實測代碼完整拆解。

基本語法與效果

public class LoggingInfo implements Serializable {
    private Date loggingDate = new Date();
    private String uid;
    private transient String pwd; // 不會被序列化

    public LoggingInfo(String user, String password) {
        this.uid = user;
        this.pwd = password;
    }
}

序列化後反序列化,pwd 為 null (物件預設值),而非建構子設定的值。

核心機制:反序列化繞過建構子

JVM 反序列化時不呼叫任何建構子,而是直接分配記憶體並逐欄位恢復數值。因此:

  • transient 欄位無資料來源 → 保持型別預設值 (null/0/false)
  • 即使建構子給了預設值 (pwd = "guest"),反序列化後依然是 null

實測驗證代碼

public class TransientDemo {
    static class GuestInfo implements Serializable {
        private String uid = "guest";
        private transient String pwd = "guest"; // 建構子/預設值都給 guest

        @Override public String toString() {
            return "uid=" + uid + ", pwd=" + (pwd == null ? "NULL" : pwd);
        }
    }

    public static void main(String[] args) throws Exception {
        GuestInfo original = new GuestInfo();
        System.out.println("原始物件: " + original); // uid=guest, pwd=guest

        // 序列化
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("guest.ser"))) {
            oos.writeObject(original);
        }

        // 反序列化
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("guest.ser"))) {
            GuestInfo restored = (GuestInfo) ois.readObject();
            System.out.println("反序列化: " + restored); // uid=guest, pwd=NULL
        }
    }
}

進階應用:自定義序列化邏輯

若需 transient 欄位反序列化後有特定值,實作 readObject:

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
    in.defaultReadObject(); // 先恢復非 transient 欄位
    this.pwd = "DEFAULT_PWD"; // 手動給預設值
    // 或從外部配置、金鑰庫載入真實密碼
}

常見誤區釐清

誤區事實
static 欄位需加 transient 才不序列化static 欄位屬於類、不屬於實例,天然不參與序列化
final + transient 會報錯可共存,但 final transient 欄位反序列化後無法賦值 (編譯期常量除外)
transient 能防止敏感資料洩漏僅防序列化洩漏,記憶體傾印、日誌、toString 仍可能暴露

最佳實踐清單

  • 密碼、Token、Session ID、資料庫連線物件 → 必加 transient
  • 衍生/可計算欄位 (如 fullName = firstName + lastName) → 加 transient,readObject 重算
  • 大型非必要快取資料 → 加 transient 減小序列化體積
  • 搭配 serialVersionUID 確保版本相容
  • Java 9+ 考慮 ObjectInputFilter 防反序列化攻擊

結語

transient 看似簡單,實則牽扯 JVM 物件佈局、序列化協議、安全審計等深層機制。掌握「繞過建構子、預設值失效、靜態天然排除」三大鐵律,才能在分散式系統、快取同步、安全合規場景下寫出零 Bug 的序列化代碼。

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