Java 只有值傳遞 (Pass by Value)。無論基本類型還是引用類型,方法調用時都是將實參的值的副本傳給形參。區別在於:
public static void test(boolean flag) {
flag = !flag; // 修改副本
System.out.println("方法內: " + flag); // false
}
public static void main(String[] args) {
boolean flag = true;
System.out.println("調用前: " + flag); // true
test(flag);
System.out.println("調用後: " + flag); // true,原值未變
}
引用是指向堆中對象的「地址句柄」,佔用棧內存。多個引用可指向同一對象:
StringBuffer a = new StringBuffer("Hello");
StringBuffer b = a; // b 複製了 a 的引用值 (地址)
b.append(", World");
System.out.println(a); // Hello, World — 同一對象被修改
public static void test(StringBuffer sb) {
sb.append(", World!"); // 通過引用副本找到原對象,修改內容
}
public static void main(String[] args) {
StringBuffer s = new StringBuffer("Hello");
test(s);
System.out.println(s); // Hello, World! — 原對象被改變
}
誤以為是引用傳遞:實際是引用值副本指向同一對象,通過副本操作對象內部狀態。
public static void test(String str) {
str = "World"; // 修改形參引用指向新對象
}
public static void main(String[] args) {
String s = "Hello";
test(s);
System.out.println(s); // Hello — 原引用仍指向 "Hello"
}
證明是值傳遞:形參 str 是實參 s 的引用副本,str = "World" 只是讓副本指向新對象,不影響原引用 s。
源於 C/C++ 程序員類比 指針傳遞:
| C/C++ | Java |
|---|---|
| 值傳遞:無法修改原值 | 值傳遞:基本類型同理 |
| 指針傳遞:可通過指針修改原值 | 引用值傳遞:可通過引用修改對象內部狀態 |
| 指針可算術運算、直接訪問內存 | 引用不可運算、不暴露地址、GC 管理 |
Java 設計者有意移除指針,保留引用,簡化內存管理,但參數傳遞機制本質未變:始終傳遞值的副本。
Java 參數傳遞統一為值傳遞。理解「引用值」是地址副本,而非對象本身,是避免 Bug、設計清晰 API 的關鍵。