Java 取消了 C/C++ 顯式指針,但 new 返回的本質是對象在堆中的地址——即引用。引用是訪問對象的唯一途徑。
void changePrimitive(int x) { x = 20; }
int a = 10;
changePrimitive(a); // a 仍為 10
方法接收參數的副本,修改不影響原變量。
void changeObject(Point p) { p.x = 100; } // 修改對象內部狀態
Point pt = new Point(0,0);
changeObject(pt); // pt.x 變為 100
void reassign(Point p) { p = new Point(99,99); } // 修改引用本身
reassign(pt); // pt 仍指向原對象 (100,0),未變
核心結論:Java 只有值傳遞。傳遞對象時,傳遞的是引用的副本。副本指向同一對象,可修改對象內容;但無法在方法內讓原引用指向新對象。
Point a = new Point(1,1);
Point b = a; // b 指向同一對象
b.x = 5;
System.out.println(a.x); // 5
List list = new ArrayList<>();
StringBuilder sb = new StringBuilder("A");
list.add(sb);
sb.append("B");
list.add(sb);
// list 中兩個元素均指向同一 StringBuilder,內容均為 "AB"
賦值只能複製引用,無法創建獨立副本。clone() 創建新對象並複製字段值。
Object.clone() 行為。class Shallow implements Cloneable {
int[] arr;
@Override protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
Shallow s1 = new Shallow(); s1.arr = new int[]{1,2};
Shallow s2 = (Shallow) s1.clone();
s2.arr[0] = 99;
System.out.println(s1.arr[0]); // 99 —— 共享數組!
clone() 手動拷貝、序列化反序列化、構造函數拷貝、工具庫。class Deep implements Cloneable {
int[] arr;
@Override protected Object clone() throws CloneNotSupportedException {
Deep d = (Deep) super.clone();
d.arr = arr.clone(); // 手動拷貝數組
return d;
}
}
| 方式 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| 重寫 clone() 手動拷貝 | 性能高、可控 | 代碼繁瑣、維護成本高、易漏字段 | 簡單對象、性能敏感 |
| 序列化/反序列化 | 通用、自動處理對象圖、支持循環引用 | 需實現 Serializable、性能差、不支持 transient | 複雜對象圖、非高頻調用 |
| JSON 序列化 | 跨語言、可讀、庫成熟 | 性能一般、不支持所有類型、需無參構造器 | DTO、配置對象、跨進程傳輸 |
| 構造函數/工廠方法拷貝 | 清晰、類型安全、無反射 | 需手動編寫、繼承體系麻煩 | 不可變對象、值對象 |
| 第三方庫 | 一行代碼、功能全 | 引入依賴、反射/序列化有開銷 | 通用場景、快速開發 |
Cloneable、重寫 clone() 為 public、處理深拷貝、文檔說明拷貝深度。new ArrayList<>(list)(淺)、Stream/map 收集(深)。Arrays.copyOf()、clone()、System.arraycopy()。Java 引用機制是「引用的值傳遞」,理解這一點能避免 90% 的參數傳遞誤解。Clone 是創建對象副本的標準手段,淺拷貝是默認行為,深拷貝需顯式實現。現代開發中,不可變設計 + 構造函數拷貝往往比 clone() 更優雅、更安全。