Object obj2 = obj1; 僅複製引用,雙方指向同一堆內存對象,修改一方影響另一方。克隆目的是**創建獨立副本**,保留當前對象狀態(字段值),互不干擾。new 創建對象屬性為初始值,無法保留運行時修改後的狀態。
Cloneable:標記接口(無方法),聲明「我支持克隆」。protected native Object clone():Native 方法,執行**逐位複製(Shallow Copy)**:基本類型複製值,引用類型複製引用地址。Cloneable 調用 clone() 拋 CloneNotSupportedException。public class Student implements Cloneable {
private int number;
private String name; // String 不可變,淺克隆安全
@Override
public Student clone() {
try {
return (Student) super.clone(); // 逐位複製
} catch (CloneNotSupportedException e) {
throw new AssertionError(); // 不可能發生
}
}
// getter/setter
}
測試:stu2 = stu1.clone(); stu2.setNumber(999); → stu1.number 不變,**基本類型、不可變對象(String、包裝類)淺克隆即安全**。
class Address { String city; }
class Student implements Cloneable {
private Address address; // 可變引用類型
// ...
}
淺克隆下 stu1.address == stu2.address,修改 stu2.address.city 會影響 stu1。**必須深克隆**。
class Address implements Cloneable {
private String city;
@Override public Address clone() {
try { return (Address) super.clone(); }
catch (CloneNotSupportedException e) { throw new AssertionError(); }
}
}
class Student implements Cloneable {
private Address address;
@Override public Student clone() {
Student stu = (Student) super.clone(); // 淺複製基本字段
stu.address = this.address.clone(); // 手動深複製引用字段
return stu;
}
}
缺點:引用層級深、字段多時代碼繁瑣,易漏字段。
import java.io.*;
public class DeepCloneUtil {
@SuppressWarnings("unchecked")
public static <T extends Serializable> T deepClone(T obj) {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos)) {
oos.writeObject(obj); // 序列化到字節數組(副本)
try (ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais)) {
return (T) ois.readObject(); // 反序列化生成新對象圖
}
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException("深克隆失敗", e);
}
}
}
使用:Student stu2 = DeepCloneUtil.deepClone(stu1);
優點:
Serializable,**比運行期拋 CloneNotSupportedException 更早發現問題**。條件:對象及所有可達對象必須實現 Serializable,建議顯式聲明 serialVersionUID。
public Object clone() {
Date d = (Date) super.clone();
if (cdate != null) d.cdate = (BaseCalendar.Date) cdate.clone(); // 手動深複製內部 mutable 字段
return d;
}
| 場景 | 推薦方案 |
|---|---|
| 僅基本類型 + String/不可變對象 | 實現 Cloneable + super.clone()(淺克隆即可) |
| 少量可變引用字段,層級固定 | 手動遞歸 clone(),控制精確 |
| 復雜對象圖、多層嵌套、集合容器 | 序列化深克隆(通用、可維護) |
| 高性能熱路徑(百萬級/秒) | 手寫拷貝構造函數 / MapStruct / 自定義字節碼生成 |