首先,咱們知道 HashMap 的底層實現是開放地址法 + 鏈地址法的方式來實現。算法
即數組 + 鏈表的實現方式,經過計算哈希值,找到數組對應的位置,若是已存在元素,就加到這個位置的鏈表上。在 Java 8 以後,鏈表過長還會轉化爲紅黑樹。編程
這個數組並非一開始就很大,而是隨着 HashMap 裏面的值變多,達到 LoadFactor 的界限以後,就會擴容。剛開始的數組很小,默認只有 16。數組
這個數組大小必定是 2 的 n 次方,由於找到數組對應的位置須要經過取餘計算,取餘計算是一個很耗費性能的計算,而對 2 的 n 次方取餘就是對 2 的 n 次方減一取與運算。因此保持數組大小爲 2 的 n 次方,這樣就能夠保證計算位置高效。微信
那麼這個哈希值到底是怎麼計算的呢?假設就是用 Key 的哈希值直接計算。假設有以下兩個 key,哈希值分別是:性能
key1:優化
0000 0000 0010 1111 1001 0000 0110 1101
key2:code
0000 0000 0010 0000 1001 0000 0110 1101
若是直接使用數組默認大小,取餘以後 key1 與 key2 就會到數組同一個下標。其實 key1 和 key2 的高位是不同的。blog
因爲數組是從小到達擴容的,爲了優化高位被忽略這個問題,HashMap 源碼中對於計算哈希值作了優化,採用高位16位組成的數字與源哈希值取異或而生成的哈希值做爲用來計算 HashMap 的數組位置的哈希值:源碼
static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }
爲何要用異或?首先,對於一個數字,轉換成二進制以後,其中爲的 1 的位置表明這個數字的特性.對於異或運算,若是a、b兩個值不相同,則異或結果爲1。若是a、b兩個值相同,異或結果爲0。0與0異或是0,0與1異或是1,這樣至關於讓高位的特性在低位得以體現,因此採用這種算法,減小碰撞。hash
微信搜索「個人編程喵」關注公衆號,每日一刷,輕鬆提高技術,斬獲各類offer: