Java源碼之HashMap的hash篇

提到哈希,咱們腦殼中立馬就會閃過一個方法,就是hashCode(),沒錯。就是這個!
咱們知道HashMap是經過 數組+鏈表 的結構進行數據存儲的,有數組就會有索引,而HashMap內的數據要存儲在哪塊索引上,則是基於HashMap內部的hash方法計算出來的。
咱們經常使用的 get put 也離不開這個 hash 方法。
咱們先從hash方法入手!java

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

首先經過 hashCode() 方法獲得 h ,而後在把 h 無符號右移16位,最後經過異或算法獲得hash值,咱們找個key展開運算一下
假設有一個key算法

String key = "hello world";

那麼這個key的hashCode的二進制爲
0110 1010 1110 1111 1110 0010 1100 0100
而後把這個二進制數據向右無符號移動16位,獲得以下
0000 0000 0000 0000 0110 1010 1110 1111
最後經過把高16位和低16位作異或運算均勻分佈
0110 1010 1110 1111 1000 1000 0010 1011
給hash作異或運算主要仍是爲了下降hash衝突的機率(這個是查閱資料得知的)數組

咱們說完hash的運算過程後,看一下HashMap裏邊都是哪裏有用到吧code

public V get(Object key) {
    Node<K,V> e;
    return (e = getNode(hash(key), key)) == null ? null : e.value;
}
public boolean containsKey(Object key) {
    return getNode(hash(key), key) != null;
}
public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

這三個方法,算是HashMap內最經常使用的三個方法了,能夠看到從應用層傳遞進來的key所有都通過了hash(key)而比較細心的朋友們還會發現HashMap內數組的索引,是經過 i = (n - 1) & hash 計算得出的索引

咱們接下來在展開一下索引計算公式
n是HashMap內的哈希表的長度,默認是16,每次擴容都是一倍一倍的擴容,就是 16 << 1 ,咱們拿16來展開運算,而hash用上面的key來繼續運算get

i = (16 - 1) & hashhash

15的二進制結果是
0000 0000 0000 0000 0000 0000 0000 1111class

hash的再拿過來用吧~(十進制:1794082859)
0110 1010 1110 1111 1000 1000 0010 1011效率

在經過&運算,能夠獲得(十進制:11)
0000 0000 0000 0000 0000 0000 0000 1011二進制

十進制計算:
1794082859 & 15 = 11
1794082859 % 16 = 11

首先n在HashMap裏的設定是永遠都是2次冪,由於 2次冪 & hash(key) 等價於 hash(key) % n
而衆所周知,& 比 % 效率要高10倍的。
但這個公式只有 n 是2次冪的時候才成立,因此纔有了2次冪的設定。

HashMap的索引都是經過這個算法得出來的,因此HashMap查找起來特別快~

好了,經過這篇文章,你們應該也對HashMap的hash有點概念了。

相關文章
相關標籤/搜索