序列化:將 Java 物件轉換為位元組序列(byte stream)的過程,便於網路傳輸、檔案持久化或跨進程通訊。
反序列化:將位元組序列還原為 Java 物件的逆向過程。
為什麼需要序列化?
網路傳輸、檔案儲存、RPC 呼叫、分散式快取(Redis)、Session 持久化等場景,本質上都只能傳遞二進制資料。序列化是物件與二進制資料之間的橋樑。
public class Student implements Serializable {
private static final long serialVersionUID = 3404072173323892464L;
private String name;
private transient String id; // 不參與序列化
private String age;
// 建構子、getter/setter、toString()...
}
序列化操作:
// 寫入(序列化)
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("student.dat"));
oos.writeObject(student);
oos.close();
// 讀取(反序列化)
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("student.dat"));
Student s = (Student) ois.readObject();
ois.close();
在類中私有定義兩個方法,JVM 會自動呼叫:
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject(); // 執行預設序列化(非 transient 欄位)
oos.writeUTF(id); // 手動序列化 transient 欄位
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject(); // 執行預設反序列化
id = ois.readUTF(); // 手動反序列化 transient 欄位
}
應用場景:加密敏感欄位、自定義序列化格式、處理非 Serializable 的第三方物件。
public class Student implements Externalizable {
private String name;
private String id;
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(name);
out.writeObject(id); // 必須顯式寫入所有需持久化欄位
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
name = (String) in.readObject();
id = (String) in.readObject(); // 讀取順序必須與寫入順序一致
}
}
關鍵差異:
writeObject/readObject 不會被呼叫)InvalidClassException| 實現方式 | 反序列化時是否呼叫建構子 | 說明 |
|---|---|---|
| Serializable | 否 | 直接分配記憶體並填充欄位,繞過建構子 |
| Externalizable | 是(無參建構子) | 先 newInstance() 再呼叫 readExternal() |