HashMap的最大容量為什麼是2的30次方(1左移30)?
文章目錄
引言
在閱讀hashmap的原始碼過程中,我看到了關於hashmap最大容量的限制,併產生了一絲疑問。
/**
* The maximum capacity, used if a higher value is implicitly specified
* by either of the constructors with arguments.
* MUST be a power of two <= 1<<30.
*/
static final int MAXIMUM_CAPACITY = 1 << 30;
為啥最大容量是 1 << 30?
探究過程1 – 為什麼是30
首先是 <<
這個操作符必須要理解,在一般情況下 1 << x
等於 2^x
。這是左移操作符,對二進位制進行左移。
來看1 << 30。它代表將1左移30位,也就是0010...0
來看這樣一段程式碼:
public static void main(String[] args){
for (int i = 30; i <= 33; i++) {
System. out.println("1 << "+ i +" = "+(1 << i));
}
System.out.println("1 << -1 = " + (1 << -1));
}
輸出結果為:
1 << 30 = 1073741824
1 << 31 = -2147483648
1 << 32 = 1
1 << 33 = 2
1 << -1 = -2147483648
結果分析:
- int型別是32位整型,佔4個位元組。
- Java的原始型別裡沒有無符號型別。 -->所以首位是符號位 正數為0,負數為1
- java中存放的是補碼,1左移31位的為 16進位制的
0x80000000
代表的是-2147483648–>所以最大隻能是30
探究過程2 – 為什麼是 1 << 30
探究完1相信大家對 為什麼是30有一點點了解。那為什麼是 1 << 30,而不是0x7ffffff
即Integer.MAX_VALUE
我們首先看程式碼的註釋
/**
* The maximum capacity, used if a higher value is implicitly specified
* by either of the constructors with arguments.
* MUST be a power of two <= 1<<30.
*/
static final int MAXIMUM_CAPACITY = 1 << 30;
翻譯一下大概就是:如果建構函式傳入的值大於該數 ,那麼替換成該數。
ok,我們看看建構函式的呼叫:
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
this.loadFactor = loadFactor;
this.threshold = tableSizeFor(initialCapacity);
}
其中這一句:
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
看到這有很有疑問了,如果我要存的數目大於 MAXIMUM_CAPACITY,你還把我的容量縮小成 MAXIMUM_CAPACITY???
別急繼續看:在resize()方法中有一句:
if (oldCap >= MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return oldTab;
}
在這裡我們可以看到其實 hashmap的“最大容量“是Integer.MAX_VALUE;
總結
MAXIMUM_CAPACITY作為一個2的冪方中最大值,這個值的作用涉及的比較廣。其中有一點比較重要的是在hashmap中容量會確保是 2的k次方,即使你傳入的初始容量不是 2的k次方,tableSizeFor()方法也會將你的容量置為 2的k次方。這時候MAX_VALUE就代表了最大的容量值。
另外還有一點就是threshold,如果對hashmap有一點了解的人都會知道threshold = 初始容量 * 載入因子。也就是擴容的 門檻。相當於實際使用的容量。而擴容都是翻倍的擴容。那麼當容量到達MAXIMUM_CAPACITY,這時候再擴容就是 1 << 31 整型溢位。所以Integer.MAX_VALUE作為最終的容量,但是是一個threshold的身份。