HashMap之扰动函数和低位掩码
我們都知道,hashMap在實現的時候,為了尋找在數組上的位置,主要做了兩件事
int hash = hash(key); int i = indexFor(key, table.length);這個時候得到i才是數組上的位置。
?
這兩個方法詳解如下
JDK8對擾動函數的修改,只進行了一次移位(又移16bit),再和key.hashCode()做異或,如圖
static final int hash(Object key){ int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }這個散列值是不能直接拿來用的。用之前還要先做對數組的長度取模運算,得到的余數才能用來訪問數組下標。源碼中模運算是在這個indexFor( )函數里完成的。
bucketIndex = indexFor(int h, table.length);其中IndexFor代碼
1 static int indexFor(int h, int length){ 2 return h & (length - 1); 3 }indexFor代碼,正好解釋了為什么HashMap的數組長度要取2的整次冪。因為這樣(數組長度-1)正好相當于一個“低位掩碼”?!芭c”操作的結果就是散列值的高位全部歸零,只保留低位值,用來做數組下標訪問。以初始長度16為例,16-1=15。2進制表示是00000000 00000000 00001111。和某散列值做“與”操作如下,結果就是截取了最低的四位值。
但這時候問題就來了,這樣就算我的散列值分布再松散,要是只取最后幾位的話,碰撞也會很嚴重。更要命的是如果散列本身做得不好,分布上成等差數列的漏洞,恰好使最后幾個低位呈現規律性重復,就無比蛋疼。
這時候“擾動函數”的價值就體現出來了,說到這里大家應該猜出來了。看下面這個圖,
右位移16位,正好是32bit的一半,自己的高半區和低半區做異或,就是為了混合原始哈希碼的高位和低位,以此來加大低位的隨機性。而且混合后的低位摻雜了高位的部分特征,這樣高位的信息也被變相保留下來。
JDK 7做了4次右移,估計是邊際效應的原因,JDK8就只做了一次右移。
另外 JDK8在鏈表長度超過8的時候,就使用紅黑樹做存儲。這一改變大大優化了很多性能。
轉載于:https://www.cnblogs.com/lycroseup/p/7344321.html
總結
以上是生活随笔為你收集整理的HashMap之扰动函数和低位掩码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android踩坑日记1
- 下一篇: Vue或React多页应用脚手架