Java 唯一採用 值傳遞。
— 基本型別:傳遞值的副本,方法內修改不影響外部。
— 參考型別:傳遞參考的副本(記憶體位址),方法內可透過參考修改物件內部狀態,但無法替換呼叫端的參考變數指向。
public class ParamTest {
public static void main(String[] args) {
// 測試 1:基本型別
double percent = 10;
System.out.println("Before: " + percent); // 10
tripleValue(percent);
System.out.println("After: " + percent); // 10 —— 未改變
// 測試 2:物件狀態修改
Employee harry = new Employee("Harry", 50000);
System.out.println("Before: " + harry.getSalary()); // 50000
tripleSalary(harry);
System.out.println("After: " + harry.getSalary()); // 150000 —— 物件內部狀態被改變
// 測試 3:嘗試交換參考
Employee a = new Employee("Alice", 70000);
Employee b = new Employee("Bob", 60000);
System.out.println("Before a: " + a.getName()); // Alice
System.out.println("Before b: " + b.getName()); // Bob
swap(a, b);
System.out.println("After a: " + a.getName()); // Alice —— 未交換成功
System.out.println("After b: " + b.getName()); // Bob
}
// 基本型別:修改的是區域變數副本
public static void tripleValue(double x) {
x = 3 * x;
}
// 物件參考:修改物件內容(透過參考副本)
public static void tripleSalary(Employee x) {
x.raiseSalary(200); // 薪資漲 200%
}
// 物件參考:嘗試交換參考——失敗
public static void swap(Employee x, Employee y) {
Employee temp = x;
x = y; // 僅改變區域參考副本
y = temp; // 呼叫端 a、b 完全不受影響
}
}
class Employee {
private String name;
private double salary;
public Employee(String n, double s) { name = n; salary = s; }
public String getName() { return name; }
public double getSalary() { return salary; }
public void raiseSalary(double byPercent) { salary += salary * byPercent / 100; }
}
呼叫端棧框 方法棧框
┌─────────────────┐ ┌─────────────────┐
│ percent = 10 │ 值複製 ───► │ x = 10 │
└─────────────────┘ └─────────────────┘
呼叫端棧框 方法棧框 堆
┌─────────────────┐ ┌─────────────────┐
│ harry ──────────┼── 參考複製 ──► │ x ──────────────┼──► Employee("Harry", 50000)
└─────────────────┘ └─────────────────┘
▲
同一物件,狀態可改
呼叫端棧框 方法棧框
┌─────────────────┐ ┌─────────────────┐
│ a ──────────────┼── 參考複製 ──► │ x ──────────────┐
│ b ──────────────┼── 參考複製 ──► │ y ──────────────┤
└─────────────────┘ └─────────────────┘
swap 內部交換 x、y 參考,呼叫端 a、b 參考完全不變
static 方法不改變參數傳遞語義,仍是值傳遞。static 方法屬於類、不屬於實例,無法直接存取非 static 欄位/方法,但能正常接收參數並操作參考物件。tripleSalary(harry) 正是 static 方法成功修改物件狀態的例證。| 程式碼片段 | 結果 | 原因 |
|---|---|---|
void m(String s) { s = "new"; }String a = "old"; m(a); | a 仍為 "old" | String 不可變,參數 s 重新指向新字串,呼叫端 a 不變 |
void m(StringBuilder sb) { sb.append("x"); }StringBuilder b = new StringBuilder("a"); m(b); | b 變 "ax" | 同一可變物件,透過參考副本修改內容 |
void m(int[] arr) { arr = new int[5]; }int[] a = {1,2}; m(a); | a 仍指向 {1,2} | 參數 arr 重新指向新陣列,呼叫端 a 不變 |
void m(int[] arr) { arr[0] = 99; }int[] a = {1,2}; m(a); | a 變 {99,2} | 同一陣列物件,修改元素內容 |