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

深入解析 Java 複製機制:從淺層複製到深層複製的完整指南

     編輯:Java 相關知識

前言:Java 中的引用與對象

Java 語言的一大優勢在於移除了指針概念,但這也導致許多開發者混淆了「對象」與「引用」的區別。在 Java 中,所有對象操作實質上都是通過引用進行的。理解這一點至關重要,因為簡單的賦值操作(=)並不會創建新對象,而只是複製引用指向同一個對象。

引用傳遞 vs 值傳遞

Java 採用「值傳遞」機制,但對於對象而言,傳遞的是引用的值。以下代碼演示了這一行為:

public class ObjRef {
    Obj aObj = new Obj();
    int aInt = 11;

    public void changeObj(Obj inObj) {
        inObj.str = "changed value";
    }

    public void changePri(int inInt) {
        inInt = 22;
    }
    // 執行結果顯示:對象屬性被修改,基本類型不變
}

當傳遞對象時,方法內部修改會影響原對象;而基本類型傳遞的是副本,修改不影響原值。這同樣適用於賦值操作:ObjB = ObjA 只是讓兩個變量指向同一對象。

集合框架中的引用陷阱

許多開發者誤以為 Hashtable、Vector 等集合能「存儲對象」,實則它們只存儲引用。以下代碼揭示了這一問題:

StringBuffer sb = new StringBuffer();
sb.append("abc,");
ht.put("1", sb);
sb.append("def,");
ht.put("2", sb);
// 所有鍵最終指向同一個被修改過的 StringBuffer

輸出結果證明:集合中所有條目實際引用同一個不斷變化的對象。

Clone 機制詳解

當需要創建一個與現有對象內容相同但獨立的新對象時,簡單賦值無法滿足需求,必須使用 clone() 方法。

實現 Clone 的基本步驟

  1. 實現 Cloneable 接口(標記接口,無方法)
  2. 重寫 clone() 方法並設為 public
  3. 在方法中調用 super.clone()
  4. 處理 CloneNotSupportedException 異常
class CloneClass implements Cloneable {
    public int aInt;
    public Object clone() {
        CloneClass o = null;
        try {
            o = (CloneClass) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return o;
    }
}

Object.clone() 是 native 方法,效率極高,它在內存中開闢新空間並逐位複製對象內容。

淺層複製的局限性

默認的 clone() 實現是淺層複製:基本類型會被真正複製,但引用類型仍指向同一對象。

class CloneB implements Cloneable {
    public int aInt;
    public UnCloneA unCA = new UnCloneA(111);
    // 未重寫 unCA 的 clone
}

測試顯示:修改 b2.aInt 不影響 b1,但修改 b2.unCA 會影響 b1.unCA,因兩者共享同一 UnCloneA 實例。

深層複製的實現

要實現深層複製,需遞歸調用所有引用類型字段的 clone():

  1. 被引用的類也實現 Cloneable 並重寫 clone()
  2. 在父類 clone() 中顯式調用字段的 clone()
public Object clone() {
    CloneB o = (CloneB) super.clone();
    o.unCA = (UnCloneA) unCA.clone(); // 關鍵行
    return o;
}

此時修改 b2.unCA 不再影響 b1.unCA,兩者擁有獨立副本。

特殊情況處理

  • 不可克隆的類(如 StringBuffer):無法直接深層複製,需手動創建新實例:o.strBuf = new StringBuffer(strBuf.toString())
  • String 及包裝類:雖為引用類型,但因不可變特性,行為類似深層複製
  • final 類:無法通過繼承實現 clone,需採用手動複製策略

總結

理解 Java 的引用語義是正確使用 clone 的前提。淺層複製適用於僅包含基本類型或不可變對象的類;包含可變引用類型時,必須實現深層複製。選擇策略時需考慮性能、複雜度及被複製對象圖的結構。

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