serialVersionUID 使用 @Serial 註解
serialVersionUID 使用 @Serial 註解
serialVersionUID 使用 @Serial 註解
serialVersionUID 使用 @Serial 註解
這是 Java 14 引入的新功能,用於改善序列化相關欄位的可讀性和工具支援。
基本用法對比
傳統寫法(Java 13 及之前)
public class MyClass implements Serializable {
private static final long serialVersionUID = 1L;
// …
}
現代寫法(Java 14+)
import java.io.Serial;
public class MyClass implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
// …
}
@Serial 註解的適用範圍
serialVersionUID 欄位
public class Person implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
}writeObject 方法
public class Person implements Serializable {
@Serial
private static final long serialVersionUID = 1L;@Serial
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
// 自訂序列化邏輯
}
}
3. readObject 方法
@Serial
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
// 自訂反序列化邏輯
}
4. readObjectNoData 方法
@Serial
private void readObjectNoData() throws ObjectStreamException {
// 處理版本不相容情況
}
5. writeReplace 方法
@Serial
private Object writeReplace() throws ObjectStreamException {
return new SerializationProxy(this);
}
6. readResolve 方法
@Serial
private Object readResolve() throws ObjectStreamException {
return this.value;
}
完整範例
import java.io.*;
public class Employee implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private String name;
private int age;
private transient String password; // 不序列化
public Employee(String name, int age, String password) {
this.name = name;
this.age = age;
this.password = password;
}
@Serial
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
// 可以加入自訂邏輯
System.out.println("正在序列化: " + name);
}
@Serial
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
// 可以加入自訂邏輯
System.out.println("正在反序列化: " + name);
// 重設 transient 欄位
this.password = "default";
}
@Serial
private Object writeReplace() throws ObjectStreamException {
// 可以返回代理物件
return this;
}
@Serial
private Object readResolve() throws ObjectStreamException {
// 確保單例模式等
return this;
}
}
@Serial 註解的好處
- 提升可讀性
// ✅ 清楚標示這是序列化相關
@Serial
private static final long serialVersionUID = 1L;
// ❌ 沒有明確標示用途
private static final long serialVersionUID = 1L;
2. IDE 支援更好
IntelliJ IDEA、Eclipse 等可以更好地識別序列化欄位
提供更精確的程式碼檢查和重構支援
靜態分析工具支援
// SpotBugs, SonarQube 等工具可以:
// - 檢查 @Serial 註解的使用是否正確
// - 確認序列化方法簽章是否正確
// - 提供更好的序列化相關警告編譯時檢查
public class Test implements Serializable {
@Serial
private static final int serialVersionUID = 1; // 編譯器警告:應該是 long 型別@Serial
private void writeObject(ObjectInputStream out) { // 編譯器警告:參數類型錯誤
// …
}
}
何時使用
✅ 建議使用場景
新專案使用 Java 14+
重構既有的序列化程式碼
需要更好的工具支援
❌ 可以不用場景
維護舊版 Java 專案(< 14)
簡單的內部工具,序列化邏輯很少
遷移建議
批量遷移腳本
bash# 使用 sed 或 IDE 的查找替換功能
find . -name “*.java” -exec sed -i ‘s/private static final long serialVersionUID/@Serial\n private static final long serialVersionUID/g’ {} ;
逐步遷移
java// 可以混合使用,逐步加入 @Serial
public class MixedClass implements Serializable {
@Serial // 新增的
private static final long serialVersionUID = 1L;
// 舊的方法暫時保持不變
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
}
}
建議:如果使用 Java 14+,應該加上 @Serial 註解以獲得更好的開發體驗!