clone() 並宣告 publicsuper.clone()Cloneable 介面(標記介面,無方法)CloneNotSupportedExceptionObject.clone() 回傳型別無法確定,需由子類覆寫決定具體回傳型別,故設為 protected(包內可見 + 可繼承)。
JVM 透過 instanceof Cloneable 判斷是否允許克隆,未實作拋出 CloneNotSupportedException。
public class ClassA implements Cloneable {
private int id;
private String name;
private Date date; // 可變物件!
@Override
public ClassA clone() throws CloneNotSupportedException {
return (ClassA) super.clone(); // 淺拷貝:date 共享同一物件
}
}
修改 clone.date 會影響原物件。
@Override
public ClassA clone() throws CloneNotSupportedException {
ClassA cloned = (ClassA) super.clone();
cloned.date = (Date) date.clone(); // 手動深層複製可變物件
return cloned;
}
缺點:物件圖複雜時需層層 clone(),代碼繁瑣且易遺漏。
public Object deepClone() throws IOException, ClassNotFoundException {
// 冷凍:寫入位元組流
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
// 解凍:讀出新物件
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
前提:物件及所有引用物件必須實作 Serializable。不想序列化的欄位標記 transient。
實作 Serializable 後,transient 欄位會被序列化忽略,適合敏感資料或非序列化物件(如資料庫連線、執行緒)。
| 場景 | 推薦方式 | 理由 |
|---|---|---|
| 簡單物件、少量引用 | 手動深拷貝 | 效能最好、無依賴 |
| 複雜物件圖、框架整合 | 序列化深拷貝 | 一行代碼解決、不易漏 |
| 資料庫查詢、不需關聯物件 | 淺拷貝 | 效能高、符合語意 |
| 含非序列化物件 | 手動深拷貝 + transient | 序列化會失敗 |
淺/深拷貝無絕對優劣,視業務場景選擇。序列化雖有效能開銷,但對複雜物件圖是最安全、維護成本最低的方案。