子類實現 Serializable,父類未實現且包含狀態字段。預期反序列化後父類字段保持原值,實際卻重置為默認值(0/null)。
class AbstractSerializeDemo {
private int x, y;
public void init(int x, int y) { this.x = x; this.y = y; }
public int getX() { return x; }
public int getY() { return y; }
public void printXY() { System.out.println(\"x:\" + x + \";y:\" + y); }
}
public class SerializeDemo extends AbstractSerializeDemo implements Serializable {
private int z;
public SerializeDemo() { super.init(10, 50); z = 100; }
public void printZ() { super.printXY(); System.out.println(\"z:\" + z); }
// ... 測試代碼 ...
}
輸出:
x:10;y:50
z:100
x:0;y:0 <-- 父類狀態丟失!
z:100
反序列化時,JVM 嘗試調用父類的無參構造器初始化父類部分。父類未實現 Serializable,其字段不在序列化流中,故重置為默認值。
在子類中實現私有方法,手動寫入/讀取父類字段:
private void writeObject(ObjectOutputStream os) throws IOException {
os.defaultWriteObject(); // 先執行默認序列化(子類字段 z)
os.writeInt(getX()); // 手動寫入父類字段 x
os.writeInt(getY()); // 手動寫入父類字段 y
}
private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException {
is.defaultReadObject(); // 先執行默認反序列化(子類字段 z)
int x = is.readInt(); // 按寫入順序讀取
int y = is.readInt();
super.init(x, y); // 調用父類初始化方法恢復狀態
}
再次運行,輸出符合預期:
x:10;y:50
z:100
x:10;y:50
z:100
writeReplace():序列化前替換對象(返回代理對象)。readResolve():反序列化後替換對象(返回規範實例)。典型應用:保護單例模式防止反序列化產生多實例。
private Object readResolve() {
return INSTANCE; // 返回單例實例
}
private Object writeReplace() {
return INSTANCE;
}
調用順序:writeReplace → writeObject → (流傳輸) → readObject → readResolve。
註:Java Enum 內部即通過 readResolve 保證單例,建議優先使用 Enum 實現單例。
writeObject/readObject 手動處理父類字段。writeReplace/readResolve。defaultWriteObject/defaultReadObject 保留默認處理邏輯,僅補充特殊字段。