在HashMap中,默認建立的數組長度是16,也就是哈希桶個數爲16,當添加key-value的時候,會先計算出他們的哈希值(h = hash),而後用return h & (length-1)
就能夠算出一個數組下標,這個數組下標就是鍵值對應該存放的位置。java
可是,當數據較多的時候,不一樣鍵值對算出來的hash值相同,而致使最終存放的位置相同,這就是hash衝突,當出現hash衝突的時候,該位置的數據會轉變成鏈表的形式存儲,可是咱們知道,數組的存儲空間是連續的,因此能夠直接使用下標索引來查取,修改,刪除數據等操做,並且效率很高。而鏈表的存儲空間不是連續的,因此不能使用下標 索引,對每個數據的操做都要進行從頭至尾的遍歷,這樣會使效率變得很低,特別是當鏈表長度較大的時候。爲了防止鏈表長度較大,須要對數組進行動態擴容。node
數組擴容須要申請新的內存空間,而後把以前的數據進行遷移,擴容頻繁,須要耗費較多時間,效率下降,若是在使用完一半的時候擴容,空間利用率就很低,若是等快滿了再進行擴容,hash衝突的機率增大!!那麼何時開始擴容呢???數組
爲了平衡空間利用率和hash衝突(效率),設置了一個加載因子(loadFactor
),而且設置一個擴容臨界值(threshold = DEFAULT_INITIAL_CAPACITY * loadFactor
),就是說當使用了16*0.75=12個數組之後,就會進行擴容,且變爲原來的兩倍。less
先看一段源碼註釋:dom
Because TreeNodes are about twice the size of regular nodes, we * use them only when bins contain enough nodes to warrant use * (see TREEIFY_THRESHOLD). And when they become too small (due to * removal or resizing) they are converted back to plain bins. In * usages with well-distributed user hashCodes, tree bins are * rarely used. Ideally, under random hashCodes, the frequency of * nodes in bins follows a Poisson distribution * (http://en.wikipedia.org/wiki/Poisson_distribution) with a * parameter of about 0.5 on average for the default resizing * threshold of 0.75, although with a large variance because of * resizing granularity. Ignoring variance, the expected * occurrences of list size k are (exp(-0.5) * pow(0.5, k) / * factorial(k)). The first values are: * * 0: 0.60653066 * 1: 0.30326533 * 2: 0.07581633 * 3: 0.01263606 * 4: 0.00157952 * 5: 0.00015795 * 6: 0.00001316 * 7: 0.00000094 * 8: 0.00000006 * more: less than 1 in ten million
大概意思就是說,在理想狀況下,使用隨機哈希碼,節點出現的頻率在hash桶中遵循泊松分佈,同時給出了桶中元素個數和機率的對照表。從上面的表中能夠看到當桶中元素到達8個的時候,機率已經變得很是小,也就是說用0.75做爲加載因子,每一個碰撞位置的鏈表長度超過8個的機率達到了一百萬分之一。code