提到哈希,咱們腦殼中立馬就會閃過一個方法,就是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有點概念了。