Java中使用最多的數據結構基本就是ArrayList和HashMap,HashMap的原理也經常出如今各類面試題中,本文就HashMap的設計與設計原因做出一一講解,並解答面試常見的一些問題。html
HashMap是一張哈希表(即數組),表中的每一個元素都是鍵值對(Map.Entry類)。而且每一個元素都是一個鏈表(紅黑樹)的節點。而且HashMap的數組長度必定是2的次冪。面試
正常狀況下,新增節點時,會對節點進行取模運算,肯定節點在哈希表中的位置。可是當哈希表(數組)長度爲2的次冪時,取模運算能夠修改成位與運算。
源碼以下:算法
static final int hash(Object key) { if (key == null){ return 0; } int h; h = key.hashCode();返回散列值也就是hashcode // ^ :按位異或 // >>>:無符號右移,忽略符號位,空位都以0補齊 //其中n是數組的長度,即Map的數組部分初始化長度 return (n-1)&(h ^ (h >>> 16)); }
具體原理能夠參考專門講解該算法的文章:
由HashMap哈希算法引出的求餘%和與運算&轉換問題數組
咱們給 put() 方法傳遞鍵和值時,咱們先對鍵調用 hashCode() 方法,計算並返回 hashCode,而後使用HashMap內部的hash算法,將hashCode計算爲表中的具體位置,找到 Map 數組的 bucket 位置來儲存 Node 對象。數據結構
使用拉鍊法post
若是hash到的數組位置已存在對象,即爲Hash碰撞。JDK使用拉鍊法解決Hash碰撞問題。
即以原有的Node節點爲基礎,構造鏈表。將新的Node節點設爲鏈表表頭。性能
若是已原有節點爲表頭,則須要遍歷鏈表,徒增沒必要要的性能消耗優化
HashMap的查詢操做最佳時間複雜度是O(1)
,可是當表中的某個鏈表過長時,查詢該鏈表上的元素時間複雜度爲O(n)
。JDK1.8
中解決了該問題,當HashMap中某鏈表長度大於8時,鏈表會重構爲紅黑樹,這樣,HashMap的最壞時間複雜度爲O(n)
。同理,爲了避免必要的消耗,當鏈表長度小於6時,紅黑樹會從新變回鏈表設計
開放尋址法,再哈希法
感興趣能夠參看此文:
Hash碰撞和解決策略3d
當size超過閾值(**數組長度*負載因子**)時,即開始擴容,HashMap的負載因子爲0.75。
避免頻繁出現Hash碰撞,形成拉鍊過長(紅黑樹過長)。這樣會致使查詢複雜度頻繁出現最壞狀況
建立本來數組容量*2的新數組,將節點從本來的數組中遷移過去。
緣由一上文已說明,方便進行哈希運算。
緣由二是不須要從新計算Hash值(JDK1.8
優化)。通過觀測能夠發現,咱們使用的是2次冪的擴展(指長度擴爲原來2倍),因此,通過rehash以後,元素的位置要麼是在原位置,要麼是在原位置再移動2次冪的位置。對應的就是下方的resize的註釋。
/** * Initializes or doubles table size. If null, allocates in * accord with initial capacity target held in field threshold. * Otherwise, because we are using power-of-two expansion, the * elements from each bin must either stay at same index, or move * with a power of two offset in the new table. * * @return the table */ final Node<K,V>[] resize() { }
看下圖能夠明白這句話的意思,n爲table的長度,圖(a)表示擴容前的key1和key2兩種key肯定索引位置的示例,圖(b)表示擴容後key1和key2兩種key肯定索引位置的示例,其中hash1是key1對應的哈希值(也就是根據key1算出來的hashcode值)與高位與運算的結果。
元素在從新計算hash以後,由於n變爲2倍,那麼n-1的mask範圍在高位多1bit(紅色),所以新的index就會發生這樣的變化:
所以,咱們在擴充HashMap的時候,不須要像JDK1.7的實現那樣從新計算hash,只須要看看原來的hash值新增的那個bit是1仍是0就行了,是0的話索引沒變,是1的話索引變成「原索引+oldCap」。
這個是老生常談的問題了,若是順利理解了HashMap的底層結構那麼這個問題就很好理解了。equals相同的key理論上一定有相同hashCode,因此必須也重寫hashCode方法。能夠思考下若是沒重寫,在put,get過程當中會致使什麼問題。