| 場景 | 示例 | 理由 |
| 敏感數據 | 密碼、Token、銀行卡號 | 防止序列化後在磁盤/網絡明文洩露 |
| 非串行化資源 | Logger、Thread、Connection、Socket、鎖 | 這些資源無意義/無法跨進程恢復,強行序列化會報錯 |
| 衍生/可計算字段 | 面積=長×寬、全名=姓+名、緩存的 hashCode | 節省空間,反序列化後重新計算即可 |
實戰完整示例:矩形類
class Rectangle implements Serializable {
private static final long serialVersionUID = 1L;
private int width;
private int height;
private transient int area; // 衍生字段
public Rectangle(int w, int h) {
this.width = w; this.height = h; this.area = w * h;
}
public void recalcArea() { this.area = width * height; }
@Override public String toString() {
return "w=" + width + ", h=" + height + ", area=" + area;
}
}
public class TransientDemo {
public static void main(String[] args) throws Exception {
Rectangle r = new Rectangle(3, 4);
System.out.println("原始: " + r); // area=12
// 序列化
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("rect.ser"))) {
oos.writeObject(r);
}
// 反序列化
Rectangle r2;
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("rect.ser"))) {
r2 = (Rectangle) ois.readObject();
}
System.out.println("反序列化: " + r2); // area=0 (默認值)
// 恢復衍生字段
r2.recalcArea();
System.out.println("恢復後: " + r2); // area=12
}
}
源碼級案例:HashMap.modCount
// HashMap.java (JDK 8)
/**
* The number of times this HashMap has been structurally modified.
* Used to make iterators on Collection-views fail-fast.
*/
transient int modCount;
設計考量:
modCount 記錄結構性修改次數(put/remove/rehash),用於 Iterator 的 fail-fast 機制。
- 反序列化後,
modCount 歸零完全正確:新對象尚未發生任何修改,迭代器應基於新狀態計數。
- 若序列化
modCount,反序列化繼承舊值會導致:
① 新插入元素時 modCount 不連續,
② 並發場景下可能誤觸發 ConcurrentModificationException。
這體現了「序列化只保存業務狀態,不保存運行時輔助狀態」的核心原則。
進階:自定義序列化控制(writeObject/readObject)
若需對 transient 字段進行特殊處理(如加密密碼、重建連接),可實現私有方法:
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
out.writeObject(encrypt(password)); // 加密存儲
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
this.password = decrypt((String) in.readObject()); // 解密恢復
}
常見誤區
- static 字段不受 transient 影響:static 屬於類,本身不參與對象序列化(除非實現
Externalizable)。
- final 字段:若為基本類型/String 常量表達式,編譯期常量折疊會直接內聯,transient 無效;引用類型 final 字段若 transient,反序列化後為 null(需在 readObject 中賦值)。
- 父類非 Serializable:子類實現 Serializable,反序列化會調用父類無參構造器初始化父類字段,transient 僅影響當前類聲明的字段。
總結
transient 是序列化的「精準手術刀」:敏感數據不出域、運行時資源不持久化、衍生字段不佔空間。配合 serialVersionUID、自定義 writeObject/readObject,構建安全、高效、可演進的序列化方案。閱讀 JDK 集合源碼(HashMap、ArrayList、ConcurrentHashMap)中的 transient 用法,是提升架構設計能力的捷徑。
- 上一篇文章: CSS3 動畫完整指南:@keyframes 規則與 animation 屬性詳解
- 下一篇文章: Java transient 關鍵字與 volatile 混淆辨析:正確理解序列化與並發語義
Copyright ©
程式碼之家 All Rights Reserved