public class PassByValueDemo {
public static void stringUpd(String str) {
str = str.replace("j", "l"); // 生成新字符串
System.out.println("方法內: " + str); // lava
}
public static void sbUpd(StringBuffer sb) {
sb.append("c"); // 修改對象內部狀態
System.out.println("方法內: " + sb); // javac
}
public static void main(String[] args) {
String s = "java";
stringUpd(s);
System.out.println("方法外: " + s); // java ← 未變
StringBuffer sb = new StringBuffer("java");
sbUpd(sb);
System.out.println("方法外: " + sb); // javac ← 已變
}
}
Java 唯一支援「值傳遞」。基本類型傳值的副本,引用類型傳引用的副本(即地址值副本)。
String s = "java" StringBuffer sb = new StringBuffer("java")
┌─────────┐ ┌─────────┐ ┌──────────────────┐
│ s ───┼──► "java" (常量池/堆) │ sb ───┼──► [java] (堆對象) │
└─────────┘ └─────────┘ └──────────────────┘
調用 stringUpd(s) 調用 sbUpd(sb)
┌─────────┐ ┌─────────┐
│ str ────┼──► "java" │ sbParam ┼──► [java] (同一對象)
└─────────┘ └─────────┘
str = "lava" (新對象) sb.append("c") → [javac]
外部 s 仍指向 "java" 外部 sb 見到變更
| 操作 | 基本類型 / String | 可變對象 |
|---|---|---|
| 參數賦新值 | 改變局部引用指向,不影響外部 | 改變局部引用指向,不影響外部 |
| 調用方法修改內部狀態 | 不可變類無此操作 | 影響外部原對象(共享堆內存) |
| 典型類 | int, double, String, Integer, Long... | StringBuffer, ArrayList, HashMap, 自定義 Bean |
// 錯誤示範
public void swap(User a, User b) {
User tmp = a; a = b; b = tmp; // 僅交換局部引用,外部無感
}
// 正確:修改對象內部字段,或返回新對象
public void addItem(List<String> list) {
list = new ArrayList<>(); // 切斷與外部關聯
list.add("new"); // 外部列表無變化
}
public void addItemCorrect(List<String> list) {
list.add("new"); // 修改共享對象,外部可見
}
Java 只有值傳遞。理解「引用值副本」與「對象實體」的區別,是寫出無 Bug 代碼的基石。面試時若能畫出棧/堆示意圖並說清 String vs StringBuffer 差異,即可拿下此考點。