java中的hashmap裡的resize()原始碼分析:
阿新 • • 發佈:2018-12-10
java中的hashmap裡的resize()
hashmap的resize
當hashmap中的元素越來越多的時候,碰撞的機率也就越來越高(因為陣列的長度是固定的),所以為了提高查詢的效率,就要對hashmap的陣列進行擴容,陣列擴容這個操作也會出現在ArrayList中,所以這是一個通用的操作,很多人對它的效能表示過懷疑,不過想想我們的“均攤”原理,就釋然了,而在hashmap陣列擴容之後,最消耗效能的點就出現了:原陣列中的資料必須重新計算其在新陣列中的位置,並放進去,這就是resize。 那麼hashmap什麼時候進行擴容呢?當hashmap中的元素個數超過陣列大小loadFactor時,就會進行陣列擴容,loadFactor的預設值為0.75,也就是說,預設情況下,陣列大小為16,那麼當hashmap中元素個數超過16
1 final Node<K,V>[] resize() { 2 Node<K,V>[] oldTab = table; 3 int oldCap = (oldTab == null) ? 0 : oldTab.length; 4 int oldThr = threshold; 5 int newCap, newThr = 0; 6 if (oldCap > 0) { 7 // 超過最大值就不再擴充了,就只好隨你碰撞去吧 8 if (oldCap >= MAXIMUM_CAPACITY) { 9 threshold = Integer.MAX_VALUE; 10 return oldTab; 11 } 12 // 沒超過最大值,就擴充為原來的2倍 13 else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && 14 oldCap >= DEFAULT_INITIAL_CAPACITY) 15 newThr = oldThr << 1; // double threshold 16 } 17 else if (oldThr > 0) // initial capacity was placed in threshold 18 newCap = oldThr; 19 else { // zero initial threshold signifies using defaults 20 newCap = DEFAULT_INITIAL_CAPACITY; 21 newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY); 22 } 23 // 計算新的resize上限 24 if (newThr == 0) { 25 26 float ft = (float)newCap * loadFactor; 27 newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ? 28 (int)ft : Integer.MAX_VALUE); 29 } 30 threshold = newThr; 31 @SuppressWarnings({"rawtypes","unchecked"}) 32 Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap]; 33 table = newTab; 34 if (oldTab != null) { 35 // 把每個bucket都移動到新的buckets中 36 for (int j = 0; j < oldCap; ++j) { 37 Node<K,V> e; 38 if ((e = oldTab[j]) != null) { 39 oldTab[j] = null; 40 if (e.next == null) 41 newTab[e.hash & (newCap - 1)] = e; 42 else if (e instanceof TreeNode) 43 ((TreeNode<K,V>)e).split(this, newTab, j, oldCap); 44 else { // 連結串列優化重hash的程式碼塊 45 Node<K,V> loHead = null, loTail = null; 46 Node<K,V> hiHead = null, hiTail = null; 47 Node<K,V> next; 48 do { 49 next = e.next; 50 // 原索引 51 if ((e.hash & oldCap) == 0) { 52 if (loTail == null) 53 loHead = e; 54 else 55 loTail.next = e; 56 loTail = e; 57 } 58 // 原索引+oldCap 59 else { 60 if (hiTail == null) 61 hiHead = e; 62 else 63 hiTail.next = e; 64 hiTail = e; 65 } 66 } while ((e = next) != null); 67 // 原索引放到bucket裡 68 if (loTail != null) { 69 loTail.next = null; 70 newTab[j] = loHead; 71 } 72 // 原索引+oldCap放到bucket裡 73 if (hiTail != null) { 74 hiTail.next = null; 75 newTab[j + oldCap] = hiHead; 76 } 77 } 78 } 79 } 80 } 81 return newTab; 82}