現象重現
List<String> list = new ArrayList<>();
list.add("abc");
String str = list.get(0); // 獲取引用
str += "def"; // 修改引用指向的對象?
System.out.println(str); // abcdef
System.out.println(list); // [abc] ← 原元素未變!
核心原因:String 是不可變對象
list.get(0) 返回字串 "abc" 的**引用** (地址),str 指向堆中 "abc" 對象。
str += "def" 編譯器轉為 str = str + "def" → new StringBuilder().append(str).append("def").toString()。
- **產生全新字串對象
"abcdef"** 在堆中,str 引用指向新對象。
- 原
"abc" 對象**未被修改**,List 仍引用舊對象。
對比:可變對象 (如 StringBuilder) 行為不同
List<StringBuilder> list = new ArrayList<>();
list.add(new StringBuilder("abc"));
StringBuilder sb = list.get(0);
sb.append("def"); // 直接修改對象內部字元陣列
System.out.println(sb); // abcdef
System.out.println(list); // [abcdef] ← 原元素也變了!
記憶體圖解
修改前:
str ──────► "abc" ◄────── list[0]
str += "def" 後:
str ──────► "abcdef" (新對象)
list[0] ──► "abc" (舊對象不變)
總結
get() 確實返回**引用** (地址傳遞)。
- **不可變類 (String, Integer, Long 等包裝類)** 任何「修改」操作實為**建立新對象**,原引用不變。
- **可變類 (StringBuilder, ArrayList, 自定義 Bean)** 通過引用調用修改方法會影響原對象。