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

Java 對象克隆完全指南:淺拷貝、深拷貝、Cloneable 協議與不可變對象策略

     編輯:Java 相關知識

克隆協議三要件

  1. 類實現 Cloneable 接口(標記接口,無方法)。
  2. 重寫 clone() 方法,聲明為 public。
  3. 首行調用 super.clone() 獲取淺拷貝基礎。

否則拋出 CloneNotSupportedException。

淺拷貝

Object.clone() 默認行為:分配新對象,逐位複製字段值。基本類型獨立,引用類型共享同一對象。

class ClassA { int a; void doubleA() { a *= 2; } }
class ClassB implements Cloneable {
    int b;
    ClassA ca = new ClassA(11);
    public Object clone() {
        try { return super.clone(); }
        catch (CloneNotSupportedException e) { throw new AssertionError(); }
    }
}
// 測試
ClassB cb = new ClassB(); cb.b = 222;
ClassB cb2 = (ClassB) cb.clone();
cb2.b = 3333;
cb2.ca.doubleA();  // 修改共享的 ca
System.out.println(cb.ca);   // 22  ← 被影響!
System.out.println(cb2.ca);  // 22

深拷貝

在 clone() 中對可變引用字段遞歸調用 clone():

class ClassA implements Cloneable { ... public Object clone() { return super.clone(); } }
class ClassB implements Cloneable {
    int b;
    ClassA ca = new ClassA(11);
    public Object clone() {
        ClassB cb = (ClassB) super.clone();
        cb.ca = (ClassA) ca.clone();  // 關鍵:深拷貝內部對象
        return cb;
    }
}
// 測試結果:cb.ca 保持 11,cb2.ca 變為 22,互不干擾

特殊情況處理

不可變對象

String、包裝類、final 類無需深拷貝,共享安全。

無法實現 Cloneable 的第三方類

方案:複製構造器 new ThirdParty(obj)、序列化反序列化、手工構建新實例複製字段。

循環引用

需維護 Map 避免無限遞歸,或使用序列化框架(如 Kryo)自動處理。

最佳實踐清單

  • 優先考慮不可變設計,從根源避免克隆需求。
  • 需克隆時,基本類型 + 不可變引用 → 淺拷貝即可;可變引用 → 必須深拷貝。
  • 實現 clone() 時拋出不可檢查異常(如 AssertionError)包裝 CloneNotSupportedException,簡化調用端。
  • 文檔化克隆語義:是淺拷貝還是深拷貝,哪些字段共享。
  • 考慮複製構造器或靜態工廠方法替代 Cloneable(Effective Java Item 13 建議)。

克隆看似簡單,實則暗藏共享可變狀態的陷阱。明確語義、最小化可變性,才是正道。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved