public class Ques1114 implements Serializable {
private static final long serialVersionUID = 1L;
public final int num;
public Ques1114() { num = 123; }
}
public class Ques1114 implements Serializable {
private static final long serialVersionUID = 1L;
public final int num;
public Ques1114() { num = 321; } // 唯一變化
}
V1.0 對象序列化到磁碟 → 升級為 V2.0 類定義 → 反序列化讀取對象 → num 輸出多少?
輸出:123
Java 序列化規範對 final 實例變量分兩類處理:
static final 基本類型/String + 常量表達式賦值)→ 不序列化,反序列化時直接讀取類定義的常量值。本題 num 在構造器賦值,屬於「運行時賦值」,因此:
123 寫入對象流。123 賦給 num,完全跳過 V2.0 構造器中的 num = 321。上題 num = init() 方法賦值,同屬「運行時賦值」,行為完全一致,輸出同為 123。
final,改用 transient + 反序列化後重新計算(readObject())。static final 常量表達式(編譯時常量),但失去實例級差異化能力。InvalidClassException。// 序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.ser"));
oos.writeObject(new Ques1114()); // V1.0 實例,num=123
oos.close();
// 反序列化(類已換成 V2.0)
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.ser"));
Ques1114 obj = (Ques1114) ois.readObject();
System.out.println(obj.num); // 輸出 123
ois.close();
理解此機制,能有效避免分布式系統、緩存中間件、RPC 框架中因對象序列化不一致引發的業務 Bug。