Java 只有值傳遞。對於基本類型傳遞值的副本;對於引用類型傳遞引用的副本(即對象地址的副本)。
public class PrimitiveDemo {
public static void main(String[] args) {
int a = 3;
modify(a);
System.out.println("main 中 a = " + a); // 輸出 3
}
static void modify(int x) {
x = 5;
System.out.println("modify 中 x = " + x); // 輸出 5
}
}
內存圖解:main 棧幀中 a=3;調用 modify 時在新棧幀創建 x 並複製值 3。修改 x 不影響 a。
class Person {
String name;
Person(String name) { this.name = name; }
}
public class ReferenceDemo {
public static void main(String[] args) {
Person p = new Person("Alice");
changeName(p);
System.out.println("main 中 p.name = " + p.name); // 輸出 Bob
}
static void changeName(Person person) {
person.name = "Bob"; // 修改對象內部狀態
}
}
關鍵點:person 是 p 的副本,但兩個引用指向堆上同一個 Person 對象。通過副本修改對象字段,主方法可見。
public class ReferenceTrap {
public static void main(String[] args) {
Person p = new Person("Alice");
replace(p);
System.out.println("main 中 p.name = " + p.name); // 仍輸出 Alice
}
static void replace(Person person) {
person = new Person("Bob"); // person 變量指向新對象
person.name = "Charlie";
}
}
內存圖解:
main 棧幀 p → 堆地址 0x100 (Alice)replace,棧幀創建 person,複製地址 0x100person = new Person("Bob") → person 指向新地址 0x2000x200,main 的 p 仍指向 0x100,完全不受影響public class StringDemo {
public static void main(String[] args) {
String s = "Hello";
modifyString(s);
System.out.println(s); // 輸出 Hello
}
static void modifyString(String str) {
str = str + " World"; // 產生新字符串對象
// str += " World"; 同理
}
}
String 為 final 類,任何「修改」操作實際創建新對象,原引用不變,故表現同基本類型——傳值(引用值)不可變。
| 問題 | 標準回答要點 |
|---|---|
| Java 是值傳遞還是引用傳遞? | 只有值傳遞。基本類型傳值副本;引用類型傳引用副本(地址副本)。 |
| 為什麼方法內修改對象屬性外部可見? | 引用副本指向同一堆對象,通過副本訪問對象內部字段/方法修改狀態。 |
| 為什麼方法內 new 新對象賦值給參數,外部引用不變? | 參數變量持有引用副本,重新賦值只改變副本指向,不影響原引用指向。 |
| 如何在方法內修改外部引用指向? | Java 不支持。替代方案:返回新對象、使用包裝類(AtomicReference)、集合/數組容器、或重新設計 API。 |
out/ref 關鍵字,需修改對象狀態請直接修改傳入對象,或返回新對象。list.add() 影響外部;list = new ArrayList() 不影響外部。Java 僅支持值傳遞。理解「引用副本指向同一對象」與「重新賦值引用副本不影響原引用」的區別,是寫出正確、無副作用代碼的核心。面試時畫棧/堆內存圖,條理清晰講清三種情況(基本類型、引用修改狀態、引用重新賦值),即可拿下此題。