首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 淺拷貝與深拷貝完全指南:Cloneable、序列化與最佳實踐

     編輯:Java 相關知識

核心概念辨析

淺拷貝

新對象的所有字段值與原對象相同,但引用類型字段仍指向原對象引用的同一個堆內存地址。即「只複製對象本身,不複製引用對象」。

深拷貝

新對象的所有字段值與原對象相同,引用類型字段指向「被遞歸複製的新對象」,而非原引用對象。即「對象圖整體複製」。

Cloneable 接口與 clone() 方法契約

  • x.clone() != x:新舊對象非同一實例
  • x.clone().getClass() == x.getClass():類型一致
  • x.clone().equals(x):若 equals 正確實現,應為 true

關鍵規則:覆寫 clone() 必須調用 super.clone(),由 Object 分配內存並逐字段複製;實現 Cloneable 標記接口,否則拋出 CloneNotSupportedException。

代碼實戰:從淺到深

場景一:僅含基本類型與不可變對象

class Student implements Cloneable {
    String name; int age;
    // super.clone() 即為深拷貝(String 不可變)
}

場景二:包含可變引用對象

class Professor implements Cloneable { ... }
class Student implements Cloneable {
    Professor p;
    public Object clone() {
        Student o = (Student) super.clone(); // 淺拷貝
        o.p = (Professor) p.clone();         // 手動深拷貝引用對象
        return o;
    }
}

若省略 o.p = p.clone(),修改 s2.p.name 會影響 s1.p,驗證了默認 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 並自行處理。

方案對比與選型建議

方案優點缺點適用場景
手動 clone()性能高、可控、無第三方依賴代碼繁瑣、維護成本高、易漏字段核心領域模型、高頻調用、對象圖較簡單
序列化通用、自動處理複雜對象圖、代碼極少性能差(IO/反射開銷)、要求 Serializable、無法處理 transient 邏輯臨時需求、對象圖複雜、非熱點路徑、跨 JVM 複製
第三方庫API 簡潔、支持多種策略、性能優化引入依賴、學習成本通用工具類、項目已引入相關庫

最佳實踐提煉

  1. 優先考慮不可變對象設計,從根源消除拷貝需求。
  2. 必須拷貝時,**首選手動 clone()** 並配合單元測試驗證深度。
  3. 序列化方案作為備選,注意 serialVersionUID 顯式聲明與 transient 字段邏輯補全。
  4. 避免在構造器/拷貝方法中執行耗時操作或副作用邏輯。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved