HashMap 中的雜湊值計算問題
阿新 • • 發佈:2020-10-22
date: 2020-08-21 16:48:00
updated: 2020-08-21 16:52:00
HashMap 中的雜湊值計算問題
1. hash 計算
JDK1.8
HashMap原始碼
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
右移16位相當於將高16位移入到低16位,再與原hashcode做異或計算(位相同為0,不同為1)可以將高低位二進位制特徵混合起來 => 高16位沒有發生變化,但是低16位改變了
拿到的hash值會參與hashmap中陣列槽位的計算,計算公式:(n - 1) & hash,假設陣列初始槽位16個,那麼槽位計算如下:
高區的16位很有可能會被陣列槽位數的二進位制碼鎖遮蔽,如果我們不做剛才移位異或運算,那麼在計算槽位時將丟失高區特徵
雖然丟失了高區特徵,不同hashcode也可以計算出不同的槽位來,但是如果兩個hashcode很接近時,高區的特徵差異可能會導致一次雜湊碰撞。
2. 使用異或運算的原因
異或運算能更好的保留各部分的特徵,如果採用 & 運算計算出來的值會向0靠攏,採用 | 運算計算出來的值會向1靠攏
3. 為什麼槽位數必須使用2^n / 為什麼要 &length-1
為了讓雜湊後的結果更加均勻,減少hash碰撞
4. 擴容後Hash值計算
length * 2,即新增的bit位是1,在 (n - 1) & hash 時,只需要判斷新增加的這一個bit位,如果是0的話,說明索引不變,如果變成1了,索引變成 原索引+擴容前的容量大小