Java 語言的一大優勢在於移除了指針概念,但這也導致許多開發者混淆了「對象」與「引用」的區別。在 Java 中,所有對象操作實質上都是通過引用進行的。理解這一點至關重要,因為簡單的賦值操作(=)並不會創建新對象,而只是複製引用指向同一個對象。
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() 方法。
Cloneable 接口(標記接口,無方法)clone() 方法並設為 publicsuper.clone()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():
Cloneable 並重寫 clone()clone() 中顯式調用字段的 clone()public Object clone() {
CloneB o = (CloneB) super.clone();
o.unCA = (UnCloneA) unCA.clone(); // 關鍵行
return o;
}
此時修改 b2.unCA 不再影響 b1.unCA,兩者擁有獨立副本。
o.strBuf = new StringBuffer(strBuf.toString())理解 Java 的引用語義是正確使用 clone 的前提。淺層複製適用於僅包含基本類型或不可變對象的類;包含可變引用類型時,必須實現深層複製。選擇策略時需考慮性能、複雜度及被複製對象圖的結構。