一個有趣且令人困惑的代碼片段
Code A:
final ConcurrentHashMap REFS_MAPS = new ConcurrentHashMap();public void put(String key) { Ref ref = new Ref(key, "1"); ref = new Ref(key, "2"); REFS_MAPS.put(key, ref);}public Ref get(String key) { return REFS_MAPS.get(key);}
它有可能會得到"1"嗎?
錯誤的解釋
在多線程排程的情況下,相同的 key 多次同時調用 put 和 get 方法,從 REFS_MAPS 方法 get 時,正好 put 運作到 Ref ref = new Ref(key, "1"),是以就得到了“1”的值,如下所示:

這個解釋是錯誤的,不會得到“1”。
REFS_MAPS 的 hash Node 存儲指向 “ref” 對象的值,而不是對象引用。是以,當 ref 在 put() 方法時,ref 的 val 先指向堆中的“1”,後指向堆中的“2”,如下所示:
常見的困惑問題
将 put 方法改一下:
Code B:
public void put(String key) { Ref ref = new Ref(key, "1"); REFS_MAPS.put(key, ref); ref = new Ref(key, "2");}
它有可能會得到"1"嗎?
一定會是“1”,雖然 ref 的指向堆中的“2”,但是 REFS_MAPS 的 hash Node 存儲指向 “ref” 對象的值還是“1”。
再将 put 方法改一下:
Code C:
public void put(String key) { Ref ref = new Ref(key, "1"); REFS_MAPS.put(key, ref); ref.setValue("2");}
它有可能會得到"1"嗎?
不會的得到“1”,因為 ref 和 REFS_MAPS 存儲的 “ref” 對象隻指向的同一個值,當 ref 修改了值,REFS_MAPS 中 ref 的值也被修改了。
代碼背後真正的意義是什麼?
我們知道,值傳遞(pass by value)是指在調用函數時将實際參數複制一份傳遞到函數中,引用傳遞(pass by reference)是指在調用函數時将實際參數的位址直接傳遞到函數中,而 Java 隻有值傳遞。
在 Code B 中,ref = new Ref(key, "2") 會重新開辟一片記憶體空間,指派給 ref,後面的任何修改都不會改變 Ref ref = new Ref(key, "1") 的内容,這裡不是引用傳遞,如果是引用傳遞的話,REFS_MAPS 中的引用也應該會改變,但是實際上并沒有。
在 Code C 中,ref.setValue("2") 影響了 REFS_MAPS 中的值,因為這裡是把 ref 的引用的位址複制了一份,傳遞給了 REFS_MAPS。是以,ref 其實是值傳遞,把 ref 對象引用的位址當做值傳遞給了 REFS_MAPS。
是以,值傳遞和引用傳遞的差別并不是傳遞的内容。而是實參到底有沒有被複制一份給形參。