HashMap原始碼-擴容resize方法
阿新 • • 發佈:2019-01-29
環境:jdk1.8
resize方法原始碼如下:
resize方法原始碼如下:
總結:1、擴容操作首先主要的操作是給新表的容量以及閾值正確賦值2、建立新表後,要判斷節點元素是紅黑樹還是連結串列,分別做不同的處理3、處理連結串列元素時要注意雜湊衝突的元素要單獨提取出來儲存final Node<K,V>[] resize() { Node<K,V>[] oldTab = table; //獲取舊錶的容量值 int oldCap = (oldTab == null) ? 0 : oldTab.length; //獲取舊的閾值 int oldThr = threshold; //定義新的容量、新的閾值 int newCap, newThr = 0; //1.判斷舊錶容量值是否大於0 if (oldCap > 0) { //判斷舊錶容量值是否大於最大容量值,如果大於或等於,則閾值取:2<<30,且返回舊錶,這裡相當於只是調整了閾值大小,沒有對舊錶大小進行實際改變 if (oldCap >= MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return oldTab; } //初始化新容量值為舊容量值的2倍,然後與最大容量值比較,當新容量值小於最大容量值,且舊容量值大於等於預設初始化容量值,這時也對新閾值賦值為舊閾值的2倍 else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY) newThr = oldThr << 1; // double threshold } //2.這裡的前提條件是oldCap=0,說明這是第一次建立表,將對新容量賦值為舊閾值,這裡舊閾值其實就等於HashMap的初始化容量值 else if (oldThr > 0) newCap = oldThr; //3.當oldCap=0且oldThr=0的情況下,我們預設對新容量值和新閾值按初始化值進行賦值 else { newCap = DEFAULT_INITIAL_CAPACITY; newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY); } //當進入判斷條件2時,這時新閾值就會等於0 if (newThr == 0) { //根據新容量值乘以載入因子得到新閾值 float ft = (float)newCap * loadFactor; newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ? (int)ft : Integer.MAX_VALUE); } //修改全域性變數threshold的值 threshold = newThr; //定義並初始化新表,指定容量 @SuppressWarnings({"rawtypes","unchecked"}) Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap]; //修改全域性變數table的值 table = newTab; //判斷舊錶是否存在,如果存在,則需要將舊錶中的資料複製到新表中 if (oldTab != null) { //遍歷舊錶 for (int j = 0; j < oldCap; ++j) { Node<K,V> e; //判斷舊錶中的每個位置上的元素是否存在,將該元素賦值給臨時變數e if ((e = oldTab[j]) != null) { //將舊錶元素置空,有利於GC oldTab[j] = null; //因為HashMap的資料結構是陣列+連結串列,這裡需要判斷該元素所在連結串列是否有下個元素,如果沒有,則可以直接將該元素放入新表中 if (e.next == null) newTab[e.hash & (newCap - 1)] = e; //判斷該元素是否是紅黑樹節點型別,如果是,則按紅黑樹進行處理(關於紅黑樹後面會持續補充相關原始碼分析) else if (e instanceof TreeNode) ((TreeNode<K,V>)e).split(this, newTab, j, oldCap); //說明該元素所在連結串列有其他元素,需要對其他元素做處理 else { Node<K,V> loHead = null, loTail = null; Node<K,V> hiHead = null, hiTail = null; Node<K,V> next; do { //逐個取出連結串列中的元素 next = e.next; //比較hash值,這裡的目的是為了處理hash衝突,使用hiHead儲存雜湊衝突的元素 if ((e.hash & oldCap) == 0) { if (loTail == null) loHead = e; else loTail.next = e; loTail = e; } else { if (hiTail == null) hiHead = e; else hiTail.next = e; hiTail = e; } } while ((e = next) != null); //雜湊不衝突的元素放入新表與舊錶一樣的位置上 if (loTail != null) { loTail.next = null; newTab[j] = loHead; } //雜湊衝突的元素提取出來,放入新位置上 if (hiTail != null) { hiTail.next = null; newTab[j + oldCap] = hiHead; } } } } } return newTab; }