| 維度 | 淺拷貝 | 深拷貝 |
|---|---|---|
| 基本型別欄位 | 值複製 | 值複製 |
| 引用型別欄位 | 複製引用地址 (共用同一物件) | 遞歸複製引用物件 (全新物件圖) |
| 修改影響 | 修改引用物件會影響原物件 | 完全隔離,互不影響 |
| 典型實現 | Object.clone() 默認行為 | 重寫 clone() 遞歸複製 / 序列化反序列化 |
x.clone() != x (新物件)x.clone().getClass() == x.getClass() (同類型)x.clone().equals(x) (若正確實現 equals)public class Person implements Cloneable {
private String name;
private int age;
private Address address; // 引用型別
@Override
public Person clone() {
try {
Person cloned = (Person) super.clone(); // 淺拷貝
// 深拷貝引用欄位
cloned.address = this.address.clone(); // Address 需實現 Cloneable
return cloned;
} catch (CloneNotSupportedException e) {
throw new AssertionError("不可發生", e);
}
}
}
// Professor 實現 Cloneable
class Professor implements Cloneable {
String name; int age;
// getter/setter/clone()...
}
// Student 淺拷貝 (危險)
class Student implements Cloneable {
String name; int age; Professor prof;
@Override public Student clone() {
try { return (Student) super.clone(); }
catch (CloneNotSupportedException e) { throw new AssertionError(e); }
}
}
// 測試
Professor p = new Professor("王教授", 50);
Student s1 = new Student("張三", 18, p);
Student s2 = s1.clone();
s2.prof.name = "李教授"; // 修改 s2 的教授
System.out.println(s1.prof.name); // 輸出「李教授」—— s1 被污染!
class Student implements Cloneable {
// ...
@Override public Student clone() {
try {
Student cloned = (Student) super.clone();
cloned.prof = this.prof.clone(); // 關鍵:深拷貝引用物件
return cloned;
} catch (CloneNotSupportedException e) { throw new AssertionError(e); }
}
}
再次測試,s1.prof.name 保持「王教授」,隔離成功。
public 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)) {
@SuppressWarnings("unchecked")
T cloned = (T) ois.readObject();
return cloned;
}
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException("深拷貝失敗", e);
}
}
Serializable。transient 會被跳過 (需手動處理)。| 方案 | 優點 | 缺點 |
|---|---|---|
| 複製建構子 / 工廠方法 | 可讀、可控、無反射、支援不可變物件 | 需手動編寫、維護成本 |
| MapStruct / Lombok @Builder | 編譯期生成、高性能、類型安全 | 引入依賴、學習成本 |
| Jackson / Gson 序列化轉換 | 通用、支援複雜圖、可配置 | 需無參建構子、效能中等 |
| Immutable Collections / Records (Java 16+) | 天然不可變、無需拷貝 | 適用於新代碼、數據類 |
copy() / deepCopy() 方法,內部用複製建構子或 MapStruct 實現,**避免使用 clone()**。new ArrayList<>(list) (淺) / 串流 list.stream().map(Item::deepCopy).collect(toList()) (深)。淺拷貝共享引用,深拷貝遞歸複製。clone() 設計缺陷多 (需實現 Cloneable、拋受檢異常、默認淺拷貝),**現代 Java 開發強烈建議棄用 clone()**,改用複製建構子、工廠方法、MapStruct 或不可變設計。序列化深拷貝僅作為 legacy 系統兼容或通用工具方法的最後手段。