Java 永遠是「傳值呼叫」。 基本型別傳遞值的副本;物件傳遞「參考的副本」(reference value copy)。不存在 C++ 的傳參考。
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(原值未變)
}
記憶體圖:
main 棧框: flag (true) ──值複製──► test 棧框: flag (true) → 改為 false
String a = "Hello";
String b = a; // a、b 參考值相同,指向同一 "Hello" 物件
StringBuffer sb1 = new StringBuffer("Hello");
StringBuffer sb2 = sb1;
sb2.append(", World");
System.out.println(sb1); // "Hello, World" —— 同一物件被修改
public static void modify(StringBuffer sb) {
sb.append(", World"); // 透過參考副本修改「同一物件」
// sb = new StringBuffer("New"); // 重新指向新物件 → 不影響呼叫端
}
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("Hello");
modify(sb);
System.out.println(sb); // "Hello, World"
}
記憶體圖:
main 棧框: sb ──────┐
▼ (參考值複製)
modify 棧框: sb ────┼──► 堆上同一 StringBuffer 物件
│
└── sb = new ... 只改變 modify 棧框的參考,斷開連結
param = new Obj())絕不影響呼叫端。void f(T& ref) 才是真正傳參考:重新指派會改變呼叫端變數綁定的物件。String、Integer、LocalDate… 透過參考也無法修改 → 行為等同傳值,安全共享。ArrayList、StringBuilder、自訂 Bean… 若不想被修改,需防禦性複製(new ArrayList(list)、Collections.unmodifiableList)。return new Result(a, b); 或 Map/Record。List out = new ArrayList<>(); fill(out); int[] out = new int[1]; compute(out);(不推薦,可讀性差)。void compute(Callback cb) { cb.onResult(val); }