HashMap原理底層剖析

專注的阿熊發表於2021-05-07

resize 函式

  // 將集合擴容

           final Node<K,V>[] resize() {

                   Node<K,V>[] oldTab = table;

                   // 舊錶的容量

                   int oldCap = (oldTab == null) ? 0 : oldTab.length;

                   // 之前的閾值

                   int oldThr = threshold;

                   int newCap, newThr = 0;

                   // 這裡也可以說集合不為空

                   if (oldCap > 0) {

                       if (oldCap >= MAXIMUM_CAPACITY) {// 如果集合現在陣列的長度大於等於最大容量

                           threshold = Integer.MAX_VALUE;// 將整型最大的值賦值給 threshold

                           return oldTab;

                       }

                       // 當前集合陣列長度擴大二倍賦值給 newCap 小於 MAXIMUM_CAPACITY

                       // 並且集合的容量大於等於預設容量將當前閾值擴大二倍賦值給新的閾值

                       else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&

                                oldCap >= DEFAULT_INITIAL_CAPACITY)

                           newThr = oldThr << 1; // double threshold

                   }

                   // 若沒有經歷過初始化,透過建構函式指定了 initialCapcity ,將當前容量設定為大於它最小的 2 n 次方

                   else if (oldThr > 0)

                       newCap = oldThr;

                   else {               // 初始的時候長度和閾值都使用預設值

                       newCap = DEFAULT_INITIAL_CAPACITY;

                       newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);

                   }

                   // 重新計算 threshold

                   if (newThr == 0) {

                       float ft = (float)newCap * loadFactor;

                       newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?

                                 (int)ft : Integer.MAX_VALUE);

                   }

                   // 更新當前集合閾值

                   threshold = newThr;

                   // 從這裡開始便是將 oldTab 資料重新 hash 放入擴容後的 newTab

                   @SuppressWarnings({"rawtypes","unchecked"})

                       Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];

                   // table 指向的 oldTab 指向 newTab

                   table = newTab;

                   if (oldTab != null) {

                       // 遍歷雜湊表

                       for (int j = 0; j < oldCap; ++j) {

                           Node<K,V> e;

                           // 當前連結串列是否為 null 、並且將就連結串列賦值給 e

                           if ((e = oldTab[j]) != null) {

                               oldTab[j] = null;//外匯跟單gendan5.com 將原來位置的連結串列置為 null 方便垃圾回收

                               if (e.next == null)// 連結串列的長度為 1 直接將連結串列中的一個節點重新 hash 存放到相應的位置

                                   newTab[e.hash & (newCap - 1)] = e;

                               else if (e instanceof TreeNode) // 表示節點型別為樹形結構

                                   ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);

                               else { // 連結串列是非樹形結構,並且節點數量是大於 1

                                   // 將連結串列拆分為兩個子連結串列

                                   Node<K,V> loHead = null, loTail = null;

                                   Node<K,V> hiHead = null, hiTail = null;

                                   Node<K,V> next;

                                   do {  // 透過 do...while 遍歷連結串列

                                       next = e.next;

                                       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) {// 在新表的 j 位置存放連結串列

                                       loTail.next = null;

                                       newTab[j] = loHead;

                                   }

                                   if (hiTail != null) {// 在新表的 j+oldCap 位置存放連結串列

                                       hiTail.next = null;

                                       newTab[j + oldCap] = hiHead;

                                   }

                               }

                           }

                       }

                   }

                   return newTab;

               }


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69946337/viewspace-2771210/,如需轉載,請註明出處,否則將追究法律責任。

相關文章