java1.8 hash算fa優(yōu)化
HashMap的數據結構:entry數組+鏈表/紅黑樹
一澜公、根據key進行尋址(位運算)
// JDK 1.8以后的HashMap里面的一段源碼
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h ??? 16);
}
hashMap首先會根據key計算出一個hash值芝此。這段代碼也解釋了為什么hashMap的key可以為null绿渣,
如果key為null速种,則它的hash值默認為0拳喻。
1哭当、int值在計算機中是32位的,例如:
h = key.hashCode()冗澈,h=1111 1111 1111 1111 1111 1010 0111 1100
h ??? 16,h向右移動16位之后的值為:0000 0000 0000 0000 1111 1111 1111 1111
然后兩個值進行異或運算(不同取1钦勘,相同取0)。新的hash值為:
1111 1111 1111 1111 0000 0101 1000 0011
之所以這樣運算是為了亚亲,與原值相比彻采,新值的低16位同時具備了高16位
和低16位的共同的特征,盡可能的降低hash沖突朵栖。
2颊亮、在真正put的時候其實根據 if ((p = tab[i = (n - 1) & hash]) == null)
計算出位桶位置,這里之所以用了hash & (n - 1) 陨溅,其實就是用了取模運算终惑,只不過借用了
位運算的方式代替了取模,也從側面說明為什么HashMap的擴容每次都是2的冪次门扇。
二雹有、解決hash沖突
1、采用hash & (n - 1)與運算(相同為1臼寄,不同為0)
2霸奕、如果還有沖突,采用鏈表的方式吉拳,如果鏈表的長度大于8則變成紅黑樹质帅。
常用的解決hash沖突的方法有;
(1)開放定址法(2)鏈地址法(3)再哈希法(4)公共溢出區(qū)域法
三留攒、擴容
1煤惩、首先會進行rehash,即用每個hash值跟新數組的lenth-1進行與操作炼邀。
之前沖突的數據魄揉,在rehash之后,可能就不沖突了拭宁,不沖突的數據的新位置是
在老位置的基礎上加上擴容前數組的長度洛退。