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

Java transient 關鍵字深度解析:序列化中的「隱形守門人」

     編輯:Java 綜合教學

前言:什麼是 transient?

transient 英文原意是「短暫的、過渡的」。在 Java 中,它專門用於 控制對象序列化行為:被修飾的字段在序列化時會被跳過,反序列化後恢復為默認值 (對象為 null,基本類型為 0/false)。簡單說,它讓字段的生命週期「僅存於調用者內存,不寫入磁盤/網絡流」。

一、核心作用:敏感數據不落地

實現 Serializable 接口的類,默認所有非靜態、非瞬態字段都會自動序列化。但現實場景中:

  • 密碼、銀行卡號、Token 等敏感信息 絕不能 寫入文件或網絡傳輸。
  • 緩存對象中包含不可序列化的第三方庫對象 (如 DB Connection、Thread)。
  • 派生字段 (如根據出生日期計算的年齡) 反序列化後重新計算即可,無需持久化。

此時在字段前加上 transient 即可優雅解決。

二、代碼實戰:密碼字段「消失」演示

import java.io.*;

class User implements Serializable {
    private static final long serialVersionUID = 8294180014912103005L;
    private String username;
    private transient String password;  // ★ 關鍵字在這裡

    // getter/setter 省略
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    public String getPassword() { return password; }
    public void setPassword(String password) { this.password = password; }
}

public class TransientDemo {
    public static void main(String[] args) throws Exception {
        User user = new User();
        user.setUsername("lucy");
        user.setPassword("123456");

        System.out.println("序列化前: " + user.getUsername() + " / " + user.getPassword());
        // 輸出: lucy / 123456

        // 序列化到文件
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.dat"))) {
            oos.writeObject(user);
        }

        // 修改內存對象驗證反序列化是否創建新對象
        user.setUsername("modified");
        user.setPassword("modified");

        // 反序列化
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.dat"))) {
            user = (User) ois.readObject();
        }

        System.out.println("反序列化後: " + user.getUsername() + " / " + user.getPassword());
        // 輸出: lucy / null  ← password 變為 null!
    }
}

三、必知的 4 大注意點

1. 只能修飾實例變量

  • ❌ 不能修飾類、方法、局部變量、構造方法。
  • ✅ 若字段是自定義對象,該類也必須實現 Serializable。

2. static 字段天生不參與序列化

transient 加不加都一樣,因為靜態屬於類,不屬於對象實例。反序列化後靜態字段值取決於當前 JVM 中該類的最新值,而非流中數據。

class User implements Serializable {
    public static String username;      // static
    private transient String password;  // transient
}
// 反序列化後 username 為 JVM 當前值,password 為 null

3. Externalizable 接口下 transient 失效

實現 Externalizable 時,序列化完全由開發者在 writeExternal/readExternal 手動控制,transient 不再生效:

class ExternalizableDemo implements Externalizable {
    private transient String content = "我被 transient 修飾";

    @Override public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(content);  // 手寫入,照樣序列化!
    }
    @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        content = (String) in.readObject();
    }
    // 運行輸出: "我被 transient 修飾"
}

4. 反序列化後的默認值陷阱

字段類型反序列化後值
引用類型 (String, Object...)null
基本類型 (int, long...)0
booleanfalse

若業務邏輯依賴這些字段非空,需在 readObject 中手動初始化或使用 Externalizable。

四、進階技巧:自定義序列化保留 transient 字段

若既想用默認序列化機制,又想控制某個 transient 字段的寫入/讀取,可在類中私有實現:

private void writeObject(ObjectOutputStream out) throws IOException {
    out.defaultWriteObject();           // 先按默認寫入非 transient 字段
    out.writeObject(encrypt(password)); // 再手動寫入加密後的密碼
}

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
    in.defaultReadObject();             // 先按默認讀取
    this.password = decrypt((String) in.readObject()); // 解密還原
}

這樣既享受自動化便利,又能實現敏感數據加密落地。

五、總結

  • transient 是 Java 序列化的「開關」,一鍵排除字段持久化。
  • 核心場景:敏感數據保護、非序列化對象隔離、派生字段減負。
  • 牢記限制:不影響 static、不生效於 Externalizable、反序列化後為默認值。
  • 進階用法:配合 writeObject/readObject 實現加密、壓縮、延遲初始化等定制邏輯。

最佳實踐:凡是「不應離開當前 JVM 進程」的字段,果斷加上 transient。這是最低成本的安全防線。

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