首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Java HashMap 參考傳遞陷阱:為何未直接操作 map 卻發生變化?

     編輯:程式設計綜合問答

現象代碼


Map map = new HashMap();
Map ma = map;           // ma 與 map 指向同一物件
for (int i = 0; i < 3; i++) {
    Map map2 = new HashMap<>();
    map2.put("sss", "呵呵");
    ma.put(i, map2);    // 向「同一個」map 放入 map2
    ma = map2;          // ma 指向新 map2,下一輪迴圈操作的是新 map2
}
System.out.println(map); // 輸出嵌套結構:{0={...}, 1={...}, 2={...}}

記憶體模型圖解

迴圈前:
map  ──────► HashMap@100 (空)
ma   ──────► HashMap@100 (同一個)

i=0:
map2 ───► HashMap@200 {"sss":"呵呵"}
ma.put(0, map2)  → HashMap@100 變為 {0: HashMap@200}
ma = map2        → ma 現在指向 HashMap@200

i=1:
map2 ───► HashMap@300 {"sss":"呵呵"}
ma.put(1, map2)  → HashMap@200 變為 {1: HashMap@300}  (注意!操作的是上一輪的 map2)
ma = map2        → ma 指向 HashMap@300

i=2:
map2 ───► HashMap@400 {"sss":"呵呵"}
ma.put(2, map2)  → HashMap@300 變為 {2: HashMap@400}
ma = map2        → ma 指向 HashMap@400

最終 map (HashMap@100) 結構:
{ 
  0 → HashMap@200 { 1 → HashMap@300 { 2 → HashMap@400 {"sss":"呵呵"} } }
}

核心誤區

「沒有直接操作 map,為什麼 map 變了?」

因為 `ma = map` 只是複製引用 (指標),兩個變數指向同一個堆上物件。後續 `ma = map2` 只是讓 `ma` 變數指向新物件,但首輪迴圈 `ma.put(0, map2)` 已修改了原始 `map` 的內容。隨後迴圈操作的是鏈式嵌套的 `map2` 物件,最終形成鏈式結構掛在原始 `map` 下。

正確認知:Java 參數/賦值均為「傳值」

  • 基本型別:傳值副本。
  • 參考型別:傳引用副本 (記憶體地址副本)。
  • 引用副本指向同一物件 → 透過任一引用修改物件內部狀態 (如 `put`) 互可見。
  • 重新賦值引用變數 (`ma = map2`) 僅改變變數指向,不影響原物件,也不影響其他指向原物件的引用 (`map`)。

避坑指南

  1. 若需複製 Map,使用 new HashMap<>(oldMap) (淺拷貝) 或深拷貝工具。
  2. 迴圈中建立新物件後,不要重用同一引用變數累加嵌套,除非有意建立鏈式結構。
  3. 除錯時在 IDE 監視變數的 物件 ID (哈希碼),而非變數名,確認是否指向同一實例。

修正後代碼 (若目標是獨立扁平 Map)


Map> map = new HashMap<>();
for (int i = 0; i < 3; i++) {
    Map map2 = new HashMap<>();
    map2.put("sss", "呵呵");
    map.put(i, map2); // 每次都放入同一個外層 map,鍵不同
}
// 結果: {0={sss=呵呵}, 1={sss=呵呵}, 2={sss=呵呵}}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved