將對象狀態(成員變量)轉換為字節序列,用於:文件持久化、網絡傳輸、RMI 遠程調用。反序列化則還原對象。
| 特性 | Serializable | Externalizable |
|---|---|---|
| 接口方法 | 標記接口,無方法 | writeExternal/readExternal (public) |
| 默認行為 | 自動序列化非 transient/static 字段 | 完全手動控制,無默認行為 |
| 構造函數 | 無要求 | 必須有公共無參構造器 |
| 安全性 | 較高 | public 方法可被惡意調用 |
| 性能 | 反射開銷大 | 手動編碼通常更快 |
| 版本控制 | serialVersionUID | 自行管理版本邏輯 |
class Box implements Serializable {
private static int width; // static 不序列化
private transient int height; // transient 不序列化
private String name; // 正常序列化
}
反序列化時,static 字段取類當前值,transient 取默認值(int=0)。
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject(); // 先執行默認邏輯
out.writeInt(height); // 手動寫入 transient
out.writeInt(width); // 手動寫入 static
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
height = in.readInt(); // 順序必須與寫入一致
width = in.readInt();
}
Thread、Socket 等持有系統資源的對象不可序列化,強制實現會拋 NotSerializableException。解決:標記為 transient 或排除在外。
class Box implements Externalizable {
private int width, height;
private String name;
public Box() {} // 必須有無參構造器
public Box(String n, int w, int h) { name=n; width=w; height=h; }
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(name);
out.writeInt(width);
out.writeInt(height);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
name = (String) in.readObject();
width = in.readInt();
height = in.readInt();
}
}
writeObject/readObject:核心對象讀寫writeInt/readInt 等:基本類型讀寫defaultWriteObject/defaultReadObject:在自定義方法中調用默認邏輯優先使用 Serializable + serialVersionUID + 必要時 writeObject/readObject;極致性能或特殊格式需求時考慮 Externalizable。注意 transient、static 語義差異,妥善處理不可序列化字段。