Hashmap原始碼什麼要對hashcode做一次高16位異或低16位的操作

自律のalive發表於2024-03-31

image

翻譯一下就是:計算鍵的hashCode()方法,並將其高几位透過異或操作傳播到低位。因為雜湊表使用二的冪次方進行掩碼操作,那些僅在當前掩碼位之上不同的雜湊集將會一直髮生衝突。(已知的例子包括在小表中儲存連續整數的Float鍵集。)因此,我們應用了一種變換來將高位的影響向下傳播。在速度、實用性和位傳播的質量之間存在一種權衡。因為許多常見的雜湊集已經相當合理地分佈(因此不會從傳播中受益),並且因為我們使用樹來處理大的衝突集合,我們只是以最便宜的方式異或一些移位的位,以減少系統性的損耗,並且還要結合那些由於表界限而永遠不會在索引計算中使用的高位的影響。

首先需要知道的是二進位制取餘操作是怎麼一回事:
舉個例子,十進位制11對4取餘11%4 = 2 ....3,商為2,餘數為3
11的二進位制為1011,對4做除法就是右移2位,結果就是10(即是十進位制的2),丟棄11(即十進位制的3)
所以取餘操作就是拿低位的數,只要和1進行與操作即可,又因為hashmap的容量是2的冪次方進行擴容的,所以長度-1是全部1111這樣的二進位制。所以公式就變成了value &(length-1);

用上面的例子就是length=4,length-1=3 轉成二進位制為11,11對4取餘即1011&11 =11,答案很快就算出來了

二進位制取餘這裡有個問題就是如果value太大,取餘後,就會有很多數字都會有同一個餘數,也就是會放到hashmap的同一個桶裡,這樣會加大沖突。
舉個例子
1111110001 & 1111 = 0001,高位發生變化時1011110001 & 1111 = 00011001110001 & 1111 = 0001,也就是說在高位發生變化時,你最後算出來的索引都一樣了,高位位元位沒用上。
所以為了避免這種情況,HashMap將高16位與低16位進行異或,這樣可以保證高位的資料也參與到與運算中來,以增大索引的雜湊程度。

參考:https://zhuanlan.zhihu.com/p/458305988

相關文章