在 Java 開發中,transient 關鍵字與 @Transient 註解雖然名稱相似,但分別服務於 Java 原生序列化機制與 ORM 持久化框架兩個完全不同的領域。本文將通過核心原理講解、實戰代碼演示以及常見誤區分析,幫助開發者徹底掌握它們的正確使用姿勢。
當類實現 Serializable 接口時,所有非靜態、非 transient 修飾的實例變量都會被自動序列化。若某些字段(如密碼、臨時計算結果、數據庫連接對象)不希望持久化到字節流中,必須使用 transient 關鍵字修飾。
import java.io.*;
public class TransientDemo {
public static void main(String[] args) {
User user = new User();
user.setUsername("Alexia");
user.setPassword("123456"); // 敏感信息
System.out.println("序列化前: username=" + user.getUsername() + ", password=" + user.getPassword());
// 序列化到文件
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.dat"))) {
oos.writeObject(user);
} catch (IOException e) {
e.printStackTrace();
}
// 反序列化恢復
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.dat"))) {
User restored = (User) ois.readObject();
System.out.println("反序列化後: username=" + restored.getUsername() + ", password=" + restored.getPassword());
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
class User implements Serializable {
private static final long serialVersionUID = 1L;
private String username;
private transient String password; // 不參與序列化
// Getter/Setter 省略
}
輸出結果:
序列化前: username=Alexia, password=123456 反序列化後: username=Alexia, password=null
transient,static 字段都不參與序列化(反序列化後取決於當前 JVM 中該類的靜態值)在 JPA/Hibernate 等 ORM 框架中,實體類的所有非靜態、非 final 字段默認會映射為數據庫列(隱含 @Basic)。若某字段僅用於業務邏輯計算(如根據出生日期計算年齡),不需持久化到數據庫,必須標註 @Transient。
@Entity
public class Employee {
@Id
private Long id;
private Date birthDate;
@Transient // 不映射到數據庫列
public int getAge() {
return Year.now().getValue() - birthDate.toInstant()
.atZone(ZoneId.systemDefault()).toLocalDate().getYear();
}
}
許多開發者發現:給 username 加上 static 後,反序列化仍能讀到 "Alexia",似乎與「靜態變量不序列化」矛盾。
真相:靜態變量確實不參與序列化。反序列化後看到的值,是當前 JVM 中該類已加載的靜態字段值,而非從字節流恢復的數據。若在反序列化前修改了靜態值,恢復的對象將反映新值。
transient@Transient 避免數據冗餘serialVersionUID掌握 transient 與 @Transient 的邊界與聯繫,能有效避免數據洩露、持久化異常等生產事故,是 Java 進階開發者的必修內功。