hashMap源碼中的一個細節問題
以上代碼是hashMap中存儲的實現,簡單講下它的原理。hashMap實現自Map接口,他是一個雙列集合,以鍵值
對的形式儲存數據,存儲方式利用哈希表散列,數據結構是一個可變數組與鏈表相結合。這個數組中存儲的數
據是一個Entry類型的對象,該類裏面維護了一個Key、Value以及指向下一個對象的next變量,Entry類也就使
其具備了存儲鍵值對以及數組鏈表相結合的條件。
當往map中put數據時,首先判斷key值是否為空,為空則直接將value放入數組的的第一個位置,不為空,則計算
出key的hashcode值,根據hashcode的二次hash結果以及數組的大小計算出該數據所在的存儲位置,該存儲位置
的數據未必為空,因此先判斷計算出的位置上是否有數據,如果沒有,直接將value值存進去,如果有,則開始
遍歷該位置所保存的鏈表,判斷有沒有key值相同的,如果有相同的,則用value覆蓋該位置上的值,如果遍歷完
了也沒有,則將value值插在這個鏈表的頭部,插入就算完成了。
過程很簡單,但有一個細節剛開始很令人費解:
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
就是此處的判斷語句,此時我們已經找到了新存儲數據應該存儲的位置,但是在該位置上已經有數據了,而且這些
數據的key有可能和新數據的key相同,也有可能不同,因為我們雖然是使用key的hash進行的位置計算,但位置相同
的key,其內容未必相同,因此上述代碼就是判斷key值是否相同的,判斷方式就是先比較hash值,如果相同再比較
內容。此時又令人費解的是&& 後面沒有直接跟equals的比較而是((k = e.key) == key || key.equals(k)),
其實他是等價於key.equals(k),上述的寫法其實是一種優化效率的體現,因為我們經常會對某些對象重寫其equals
方法來比較內容,倘若(k = e.key) == key都返回true了,那換有必要再調用equals嗎?這種情況下就會有效率
的提升。
hashMap源碼中的一個細節問題