原始碼分析為什麼HashMap的table長度一定是2的整次冪
我們今天從原始碼入手分析一下為什麼HashMap的陣列table長度一定是2的整次冪。
首先我們先從構造方法來分析HashMap的初始化長度:
HashMap中有4個構造方法
我們來看看他們分別都是什麼
1 . HashMap();
無參的建構函式,從註釋中我們可以看出,如果我們不指定初始長度,那麼陣列的初始長度就是預設的長度,是一個靜態常量DEFAULT_LOAD_FACTOR = 16;
emmm確實是2的4次冪,但是不能說明任何問題;我們繼續看
2 . HashMap(int initialCapacity)
誒,我們找到了了一個有一個引數的構造方法,並且這個引數就是用來指定我們陣列的初始化長度的,那麼我們如果給它一個不是2的整次冪的值,它是咋辦的呢,因為這個方法呼叫了另外一個方法,我們想知道還得看一下這個裡面的構造方法,也就是第三個構造方法。
3 . HashMap (int initialCapacity, float loadFactor);
終於有了比較有價值的程式碼了,我們拋開前面的判斷,我們最後的目光就落在了最後一個方法
this.threshold = tableSizeFor(initialCapacity);
注意:雖然此處是對threshold賦值,但是後面table初始化時會將值賦給table長度,並且重新對threshold進行賦值為 capacity * loadFactory,這裡不多贅述。
這個方法最後對我們傳入的初始長度值進行了加工。再來看一下這個方法
其實從註釋我們就已經看的很清楚了,方法返回一個兩倍大小的目標容量的冪,誒
但是我們還是看一下程式碼的實現,就是“與”運算一連串的無符號右位移,我們隨便代入一個值 14
n = 14 - 1 = 13
13的2進製為
0000 0000 0000 0000 0000 0000 0000 1101
計算n = n | n >>> 1
0000 0000 0000 0000 0000 0000 0000 1101
|
0000 0000 0000 0000 0000 0000 0000 0110
結果為
0000 0000 0000 0000 0000 0000 0000 1111
然後用這個結果 = n繼續與它右位移後的值進行“或”運算,但是想在我們就發現,不管後面再計算幾次,結果已經不會變了,永遠是1111,所以最後n的結果為15。
我們再代入到最後的三目運算子中,n小於最大的容量,所以最終n的結果為16
誒,有點意思,但其實我們發現,這個運算是返回一個大於它且是最近的2的整次冪的數。
有點繞,我們換個角度
分成一個個的小區間,比如 16 < n < 32 的數就會返回32
因為 (2的整次冪 - 1) 的2進位制有效位一定都是1
4 . HashMap(Map<? extends K, ? extends V> m)
第四個構造方法是將制定的Map物件例項化成一個HashMap物件,與我們討論的問題關係不大。
至此,我們已經明白了構造方法的初始值處理。但是我們知道,陣列的長度是會改變的,當我們再map中儲存的元素超過threshold時,就會觸發擴容機制,我們的陣列長度進行擴容,我們來看一下擴容方法
resize()方法我們這裡就不過多的分析,我們只看table陣列長度變化的時候,我們從原始碼中可以清晰的看到,新陣列長度是舊陣列長度的一倍。是2倍的擴容機制。
至此我們就從原始碼中瞭解了為什麼HashMap中的陣列長度一定是2的整次冪了。如果有不對的地方希望大家指正!
還有一些問題,比如陣列長度是2的整次冪的好處,以及HashMap的原始碼分析請看我的其他文章。
相關文章
- HashMap的table長度為什麼是2的n次HashMap
- 原始碼|jdk原始碼之HashMap分析(一)原始碼JDKHashMap
- HashMap的最大容量為什麼是2的30次方(1左移30)?HashMap
- 找到一個數最接近的比它大的2的n次冪的程式碼分析
- 原始碼分析——HashMap原始碼HashMap
- HashMap 原始碼分析HashMap原始碼
- HashMap原始碼分析HashMap原始碼
- hashMap 的size 為什麼 是2的 n次方倍HashMap
- 以太坊原始碼分析(49)p2p-table.go原始碼分析原始碼Go
- 原始碼分析之 HashMap原始碼HashMap
- Java:HashMap原始碼分析JavaHashMap原始碼
- Hashmap原始碼什麼要對hashcode做一次高16位異或低16位的操作HashMap原始碼
- 【JDK原始碼分析】淺談HashMap的原理JDK原始碼HashMap
- Jdk1.7下的HashMap原始碼分析JDKHashMap原始碼
- Jdk1.8下的HashMap原始碼分析JDKHashMap原始碼
- 為什麼 HashMap 的容量大小要設定為2的N次方?HashMap
- HashMap原始碼分析 —— 一篇文章搞定HashMap面試HashMap原始碼面試
- 原始碼|jdk原始碼之HashMap分析(二)原始碼JDKHashMap
- HashMap-put原始碼分析HashMap原始碼
- JDK 1.6 HashMap 原始碼分析JDKHashMap原始碼
- hashmap原始碼面試分析HashMap原始碼面試
- HashMap原始碼實現分析HashMap原始碼
- Java原始碼分析:HashMap 1.8 相對於1.7 到底更新了什麼?Java原始碼HashMap
- 死磕 jdk原始碼之HashMap原始碼分析JDK原始碼HashMap
- 整潔的 Table View 程式碼View
- HashMap原始碼分析,未完待續HashMap原始碼
- java基礎:HashMap — 原始碼分析JavaHashMap原始碼
- HashMap原始碼分析(JDK8)HashMap原始碼JDK
- Java基礎——HashMap原始碼分析JavaHashMap原始碼
- JDK1.8 hashMap原始碼分析JDKHashMap原始碼
- HashMap原始碼分析 JDK1.8HashMap原始碼JDK
- java集合原始碼分析(六):HashMapJava原始碼HashMap
- HashMap實現原理一步一步分析(1-put方法原始碼整體過程)HashMap原始碼
- Lua Table 長度的計算
- HashMap原始碼分析(二):看完徹底瞭解HashMapHashMap原始碼
- 原始碼分析 Mybatis 的 foreach 為什麼會出現效能問題原始碼MyBatis
- Mybatis原始碼分析-整體設計(一)MyBatis原始碼
- 原始碼分析系列1:HashMap原始碼分析(基於JDK1.8)原始碼HashMapJDK