一個有趣且令人困惑的代碼片段
Code A:
final ConcurrentHashMap<String, Ref> REFS_MAPS = new ConcurrentHashMap<String, Ref>();
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)是指在調用函數(shù)時將實際參數(shù)復制一份傳遞到函數(shù)中,引用傳遞(pass by reference)是指在調用函數(shù)時將實際參數(shù)的地址直接傳遞到函數(shù)中,而 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。
所以,值傳遞和引用傳遞的區(qū)別并不是傳遞的內容。而是實參到底有沒有被復制一份給形參。