Java 只有「值傳遞」一種參數傳遞機制,但基本型別與參考型別在記憶體中的表現截然不同。本文結合堆疊與堆記憶體模型,透過程式碼與圖示詳細解析兩者差異,並釐清 String 的特殊行為。
Java 一律採用值傳遞。差別在於「傳遞的值是什麼」:
public class ParameterTransfer {
public static void main(String[] args) {
int num = 30;
System.out.println("呼叫前 num = " + num); // 30
add(num);
System.out.println("呼叫後 num = " + num); // 30(未改變)
}
public static void add(int param) {
param = 100; // 只修改區域變數副本
}
}
記憶體模型:
main 堆疊框架分配 num(位址 AD8500),值為 30。add 時,在堆疊新建框架,分配 param(位址 AD8600),複製值 30。param 只影響 AD8600,AD8500 不變。public class ParameterTransfer {
public static void main(String[] args) {
String[] array = new String[] {"huixin"};
System.out.println("呼叫前 array[0] = " + array[0]); // huixin
reset(array);
System.out.println("呼叫後 array[0] = " + array[0]); // hello, world!
}
public static void reset(String[] param) {
param[0] = "hello, world!"; // 修改堆中同一物件內容
}
}
記憶體模型:
main 堆疊 array(AD9500)存放堆位址 BE2500。array[0] 指向字串 "huixin"。reset,堆疊新建 param(AD9600),複製位址 BE2500。String 是參考型別,但表現像基本型別:
public static void change(String s) {
s = "new value"; // 重新指向新物件
}
String str = "old";
change(str);
System.out.println(str); // 仍輸出 "old"
原因有二:
String 內部封裝 char[],任何「修改」操作實際上都是建立新物件。s = "new value" 只是讓區域變數 s 指向新字串物件,不影響呼叫端的 str 引用。| 型別類別 | 傳遞內容 | 方法內修改參數本身 | 方法內修改物件內容 |
|---|---|---|---|
| 基本型別 | 值的複製 | 不影響原變數 | 不適用 |
| 參考型別 | 引用(位址)的複製 | 不影響原引用指向 | 影響原物件(共享堆記憶體) |
| String | 引用的複製 | 不影響原引用 | 不可修改內容,操作產生新物件 |
理解記憶體模型是掌握 Java 參數傳遞本質的關鍵:無論何種型別,傳遞的都是「值」的副本。