將物件狀態(非靜態、非 transient 欄位)轉為位元組流,以便持久化、網路傳輸、RMI 傳遞。反序列化為逆過程。
java.io.Serializable 標記介面(無方法)。ObjectOutputStream.writeObject() / ObjectInputStream.readObject()。transient 欄位不參與序列化。private static final long serialVersionUID = 8683452581122892189L;
InvalidClassException。若類中定義 private void writeObject(ObjectOutputStream) 與 private void readObject(ObjectInputStream),JVM 會透過反射優先調用,完全掌控二進制格式。
public class ArrayList<E> ... implements Serializable {
private static final long serialVersionUID = 8683452581122892189L;
transient Object[] elementData; // 底層陣列
private int size;
private void writeObject(ObjectOutputStream s) throws IOException {
int expectedModCount = modCount;
s.defaultWriteObject(); // 寫入非 transient 欄位
s.writeInt(size); // 寫入容量(兼容 clone)
for (int i = 0; i < size; i++) // 僅寫入實際元素
s.writeObject(elementData[i]);
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
elementData = EMPTY_ELEMENTDATA;
s.defaultReadObject(); // 讀取 size 等
s.readInt(); // 讀取容量(忽略)
if (size > 0) {
ensureCapacityInternal(size);
Object[] a = elementData;
for (int i = 0; i < size; i++)
a[i] = s.readObject(); // 逐個讀取元素
}
}
}
null,浪費空間。size 個真實元素,極大壓縮體積。size、modCount 等),再手動處理陣列內容。// ObjectOutputStream 內部邏輯簡化
if (clazz.hasWriteObjectMethod()) {
Method m = clazz.getDeclaredMethod("writeObject", ObjectOutputStream.class);
m.setAccessible(true);
m.invoke(obj, out); // 反射調用自定義方法
} else {
defaultWriteObject(obj, out);
}
writeObject 中加密密碼,readObject 解密(需金鑰管理)。ObjectInputFilter 白名單類別。Externalizable 介面完全手動控制,但維護成本高,慎用。readObjectNoData() 處理舊版本資料。