transient 英文原意是「短暫的、過渡的」。在 Java 中,它專門用於 控制對象序列化行為:被修飾的字段在序列化時會被跳過,反序列化後恢復為默認值 (對象為 null,基本類型為 0/false)。簡單說,它讓字段的生命週期「僅存於調用者內存,不寫入磁盤/網絡流」。
實現 Serializable 接口的類,默認所有非靜態、非瞬態字段都會自動序列化。但現實場景中:
此時在字段前加上 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!
}
}
Serializable。transient 加不加都一樣,因為靜態屬於類,不屬於對象實例。反序列化後靜態字段值取決於當前 JVM 中該類的最新值,而非流中數據。
class User implements Serializable {
public static String username; // static
private transient String password; // transient
}
// 反序列化後 username 為 JVM 當前值,password 為 null
實現 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 修飾"
}
| 字段類型 | 反序列化後值 |
|---|---|
| 引用類型 (String, Object...) | null |
| 基本類型 (int, long...) | 0 |
| boolean | false |
若業務邏輯依賴這些字段非空,需在 readObject 中手動初始化或使用 Externalizable。
若既想用默認序列化機制,又想控制某個 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 序列化的「開關」,一鍵排除字段持久化。writeObject/readObject 實現加密、壓縮、延遲初始化等定制邏輯。最佳實踐:凡是「不應離開當前 JVM 進程」的字段,果斷加上
transient。這是最低成本的安全防線。