所有支援 clone() 的類別必須實作 java.lang.Cloneable(標記介面,無方法)。否則呼叫 clone() 會拋出 CloneNotSupportedException。
protected native Object clone() throws CloneNotSupportedException;
// @exception CloneNotSupportedException if the object's class does not support Cloneable
protected 可見性 → 子類別或同套件才能直接呼叫。public**。public class CloneableExample implements Cloneable {
private String name;
private int score;
@Override
public Object clone() throws CloneNotSupportedException {
// 1. 呼叫父類別 clone 取得淺複製
CloneableExample cloned = (CloneableExample) super.clone();
// 2. 【關鍵】深複製可變參考型別欄位
// 本例 String、int 為不可變/基本型別,無需處理
// 若有 List、Date、自訂物件等,必須在此手動新建副本
// 3. 可選:自訂複製後調整
// cloned.name = "New Name";
// cloned.score = 90;
return cloned;
}
}
| 維度 | 淺複製 | 深複製 |
|---|---|---|
| 基本型別 | 複製值 | 複製值 |
| 不可變物件 | 共享參考(安全) | 共享參考(安全) |
| 可變物件 | 共享參考 ⚠️ | 遞迴新建副本 ✅ |
| 實作成本 | 低 | 高(需手動遞迴) |
優點:完全可控、效能最好。缺點:樣板碼多、維護負擔大、易遺漏欄位。
public static T deepClone(T obj) {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(obj);
try (ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis)) {
return (T) ois.readObject();
}
} catch (Exception e) { throw new RuntimeException(e); }
}
優點:一次處理整個物件圖、無需逐欄位寫碼。缺點:效能較差、需實作 Serializable、transient 欄位會遺失。
SerializationUtils.clone(obj)Java 14+ record、Lombok @Value、Immutables 框架:
withXxx() 產生新實例(持久化資料結構)。Cloneable 並覆寫 public Object clone()。super.clone(),再手動深複製所有可變參考欄位。