| 維度 | 淺拷貝 | 深拷貝 |
|---|---|---|
| 基本類型 | 值複製 | 值複製 |
| 引用類型 | **複製引用地址** (共用同一對象) | **遞歸複製對象** (新建獨立對象) |
| 修改影響 | 修改拷貝對象的引用屬性,原對象也變 | 互不影響,完全隔離 |
| 實現方式 | Object.clone() 默認行為 | 重寫 clone() / 序列化 / 三方庫 |
Cloneable (標記接口),否則拋 CloneNotSupportedException。clone() 為 public,調用 super.clone() 獲取淺拷貝對象。x.clone() != x, x.clone().getClass() == x.getClass(), x.clone().equals(x) (若覆寫 equals)。class Professor { String name; int age; }
class Student implements Cloneable {
String name; int age; Professor prof;
public Student(String n, int a, Professor p) { name=n; age=a; prof=p; }
@Override protected Student clone() {
try { return (Student) super.clone(); } // 淺拷貝!
catch (CloneNotSupportedException e) { throw new AssertionError(); }
}
}
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); // 輸出「李四」!原對象被污染
class Professor implements Cloneable {
String name; int age;
@Override protected Professor clone() {
try { return (Professor) super.clone(); }
catch (CloneNotSupportedException e) { throw new AssertionError(); }
}
}
class Student implements Cloneable {
String name; int age; Professor prof;
@Override protected Student clone() {
Student s = (Student) super.clone(); // 淺拷貝基本類型
s.prof = prof.clone(); // 關鍵:深拷貝引用對象
return s;
}
}
// 現在 s2.prof.name = "李四" 不會影響 s1
缺點:對象圖複雜時需層層實現 Cloneable,維護成本高,循環引用會棧溢出。
import java.io.*;
public class DeepCloneUtil {
@SuppressWarnings("unchecked")
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 (IOException | ClassNotFoundException e) {
throw new RuntimeException("深拷貝失敗", e);
}
}
}
// 使用:要求所有類實現 Serializable
Student s2 = DeepCloneUtil.deepClone(s1);
優點:一行代碼處理任意複雜對象圖,自動處理循環引用。
缺點:性能較差 (IO、反射)、要求 Serializable、transient 字段不會被拷貝。
SerializationUtils.clone(obj) (序列化)、CloneUtils.clone(obj) (反射複製)。// 簡單對象: clone() ~ 50ms, 序列化 ~ 500ms, JSON ~ 800ms
// 複雜對象圖: clone() 需手寫遞歸, 序列化/JSON 更優
new Student(s1.getName(), s1.getAge(), s1.getProf()),最清晰、性能最好。@return 深拷貝副本 或 淺拷貝。深拷貝不是銀彈,**設計時減少可變共享狀態** 才是正道。