Java 序列化是將對象的狀態(數據、類型信息等)轉換為字節序列的過程,以便在網絡傳輸、文件持久化或進程間通信中使用。反序列化則是將字節序列還原為對象的逆過程。核心類包括 ObjectOutputStream(寫入/序列化)和 ObjectInputStream(讀取/反序列化)。
實現 Serializable 標記接口是序列化的前提:
public class Employee implements Serializable {
private int employeeId;
private String employeeName;
private String department;
// getter/setter 省略
}
序列化操作:
// 序列化
try (FileOutputStream fos = new FileOutputStream("employee.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos)) {
Employee emp = new Employee();
emp.setEmployeeId(101);
emp.setEmployeeName("Arpit");
emp.setDepartment("CS");
oos.writeObject(emp);
}
// 反序列化
try (FileInputStream fis = new FileInputStream("employee.ser");
ObjectInputStream ois = new ObjectInputStream(fis)) {
Employee emp = (Employee) ois.readObject();
System.out.println("Emp id: " + emp.getEmployeeId());
}
serialVersionUID 是類的版本標識,用於反序列化時驗證發送方和接收方的類版本一致。建議顯式聲明:
private static final long serialVersionUID = 1L;
若未聲明,JVM 會根據類結構自動生成,類結構變更會導致 InvalidClassException。
序列化對象時,其引用的所有對象會自動被序列化(對象圖)。但所有被引用的類必須實現 Serializable,否則拋出 NotSerializableException。
若引用類不可序列化且無法修改源碼:
transient 跳過序列化(反序列化後為 null)writeObject/readObject 手動處理字段讀寫自定義序列化示例:
private transient Address address; // 跳過默認序列化
private void writeObject(ObjectOutputStream os) throws IOException {
os.defaultWriteObject(); // 先寫入非 transient 字段
os.writeInt(address.getHomeNo()); // 手動寫入 Address 字段
os.writeObject(address.getStreet());
os.writeObject(address.getCity());
}
private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException {
is.defaultReadObject(); // 先讀取非 transient 字段
int homeNo = is.readInt(); // 按寫入順序讀取
String street = (String) is.readObject();
String city = (String) is.readObject();
address = new Address(homeNo, street, city);
}
關鍵點:讀取順序必須與寫入順序完全一致。
| 父類狀態 | 子類序列化行為 |
|---|---|
| 父類實現 Serializable | 子類自動可序列化,父類字段正常序列化 |
| 父類未實現 Serializable | 反序列化時調用父類無參構造器初始化父類字段,子類字段正常還原 |
| 父類可序列化,但子類不想序列化 | 子類實現 writeObject/readObject 並拋出 NotSerializableException |
static)不參與序列化,屬於類級別而非對象級別transient 字段被跳過,反序列化後為默認值(對象為 null)readResolve() 防止反序列化破壞單例serialVersionUIDtransient,敏感數據(密碼等)必須標記