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

Java Object clone() 方法深度解析:淺拷貝與深拷貝完整指南

     編輯:Java 相關知識

前言

在 Java 開發中,物件複製是常見需求。Object.clone() 作為原生複製機制,雖然使用頻率不如建構式複製或序列化高,但理解其運作原理對掌握 Java 記憶體模型至關重要。本文將從方法簽名、淺拷貝與深拷貝差異、實作範例三個維度全面解析。

一、clone() 方法簽名解析

protected native Object clone() throws CloneNotSupportedException

1. native 關鍵字

表示此方法為本地方法,由 C/C++ 實現,直接操作記憶體,執行效率高於純 Java 方法。

2. protected 修飾符

預設為 protected,子類覆寫時通常改為 public,才能讓外部類別呼叫。若保持 protected,僅限同套件或子類存取。

3. 拋出 CloneNotSupportedException

類別必須實作 java.lang.Cloneable 介面(標記介面,無方法),否則呼叫 clone() 會拋出此異常。這是 Java 設計的保護機制,防止不可複製的物件被誤複製。

二、clone() 的核心作用

Java 參考型別變數儲存的是記憶體地址。單純使用 = 指派只是複製參考,兩個變數指向同一物件,修改其中一個會影響另一個。

Person p1 = new Person();
Person p2 = p1; // 同一記憶體地址

使用 clone() 可建立獨立副本,兩者擁有不同記憶體地址:

Person p1 = new Person();
Person p2 = p1.clone(); // 不同記憶體地址

三、淺拷貝 vs 深拷貝

1. 淺拷貝

僅複製物件本身,不複製內部參考型別欄位。呼叫 super.clone() 即為淺拷貝。複製後物件地址不同,但內部參考欄位仍指向同一記憶體。

public class ShallowClone implements Cloneable {
    public String name;
    public int age;
    public Person person;

    @Override
    public ShallowClone clone() {
        try {
            return (ShallowClone) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }
}

執行結果:

before clone: c1.person = Person@2dcb25f1
after clone:  c2.person = Person@2dcb25f1  // 同一地址

2. 深拷貝

複製物件的同時,遞迴複製所有參考型別欄位。需手動在 clone() 中複製每個參考欄位。

public class DeepClone implements Cloneable {
    public String name;
    public int age;
    public Person person;

    @Override
    public DeepClone clone() {
        try {
            DeepClone c = (DeepClone) super.clone();
            c.person = person.clone(); // 手動複製參考欄位
            return c;
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }
}

執行結果:

before clone: c1.person = Person@2dcb25f1
after clone:  c2.person = Person@70535b58  // 不同地址

四、最佳實踐建議

  • 優先考慮替代方案:建構式複製、靜態工廠方法、序列化(Jackson/Gson)通常比 clone() 更安全、可讀性更高。
  • 實作 Cloneable 時務必覆寫 clone():並處理深拷貝邏輯。
  • 不可變物件無需 clone:String、Integer 等本身不可變,直接共用參考即可。
  • 文件化複製行為:明確說明是淺拷貝還是深拷貝。

五、總結

clone() 是 Java 早期提供的物件複製機制,採用淺拷貝預設行為。深拷貝需開發者手動實作。現代開發中,建議優先使用建構式複製或序列化框架,僅在效能極度敏感且物件結構簡單時考慮 clone()。

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