HashMap原始碼__tableSizeFor方法解析
tableSizeFor(int cap)方法返回不小於指定引數cap的最小2的整數次冪,具體是怎麼實現的呢?看原始碼!
/** * Returns a power of two size for the given target capacity. */ static final int tableSizeFor(int cap) { int n = cap - 1; n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16; return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; }
1)為什麼cap要減一?
2)|=是什麼?
3)>>>又是什麼?
4)為什麼要返回n+1
先解釋一下"|"是什麼
這裡的“|”是叫做位或運算,百度百科這樣解釋到:按位或運算子“|”是雙目運算子。其功能是參與運算的兩數各對應的二進位相或。只要對應的2個二進位有一個為1時,結果位就為1。當參與運算的是負數時,參與兩個數均以補碼出現。
假設使用8位來儲存數字,下面用一張圖來說明下位或運算: 8|1
十進位制8的二進位制表示為圖中的A : 00001000
十進位制1的二進位制表示為圖中的B : 00000001
從圖中可以看出A從右向左第四個位為1,B從右向左第一個位為1,其餘位都為0,因此結果的第一個和第四個位都為1,結果就是00001001轉換為十進位制就是9,因此 8 | 1 = 9 。
A |= B 的意思就是 A = A | B
>>>表示無符號右移
也叫邏輯右移,即若該數為正,則高位補0,而若該數為負數,則右移後高位同樣補0。
假設使用8位來儲存數字,下面用一張圖來說明下右移運算: 8>>>1
8>>>1表示將8右移一位,如圖所示:右移後高位也就是藍色部分補0,低位也就是紅色部分直接捨棄,結果就變成了0000100轉換為十進位制就是4,因此 8 >>> 1 = 4
明白了>>>和 | 的作用就可以來解釋上面的原始碼了,
假設cap=9,n = cap - 1 = 8( 至於為什麼需要減一待會兒再說)
n |= n >>> 1; 也就是 n = n | (n>>>1)
在java中int佔4個位元組也就是32位,因此8的二進位制表示為:
00000000......00001000 中間省略16個0
00000000......00000100 8>>>1
00000000......00001100 8 |= 8>>>1 結果轉換為十進位制為:12
00000000......00000011 12>>>2
00000000......00001111 12 |= 12>>>1 結果轉化為十進位制為:15
00000000......00000000 15>>>4
00000000......00001111 15 |= 15>>>4 結果轉化為十進位制為:15
00000000......00000000 15>>>8
00000000......00001111 15 |= 15>>>8 結果轉化為十進位制為:15
00000000......00000000 15>>>16
00000000......00001111 15 |= 15>>>16 結果轉化為十進位制為:15
最後返回 n+1 也就是 16
上面的操作其實就是把 8 的二進位制表示 00000000......00001000,把 1 後面的 0 全部變成了000000000......0001111.
為什麼 n+1 之後就是2的整數次冪呢?
看一下二進位制是如何轉換為十進位制的就明白了
二進位制轉換為十進位制:
設一個n位的二進位制的位數從右至左依次為0~n位,那麼從0~n位分別乘於2的n次冪的和即為該二進位制的十進位制形式。
00000001 的十進位制表示為 1 * 2^0 = 1
00000001 加一之後就變成了 00000010 轉換為十進位制就是 0*2^0 + 1*2^1 = 0 + 2 = 2
00000011 的十進位制表示為 1*2^0 + 1*2^1 = 3
00000011 加一之後就變成了00000100 轉換為十進位制就是 0*2^0 + 0*2^1 + 2*2^2 = 0 + 0 + 4 = 4
00000111 的十進位制表示為 1*2^0 + 1*2^1 + 1*2^2 = 7
00000111加一之後就變成了00001000 轉換為十進位制就是 0*2^0 + 0*2^1 + 0*2^2 + 1*2^3 + = 0 + 0 + 0 + 8 = 8
為什麼要對cap進行減一操作呢?
這樣就可以避免當cap已經是2的整數次冪時,再對cap進行一次求次冪操作,比如:cap=16,如果沒有減一結果就會變成32,而16已經符合HashMap的要求了.