1. 程式人生 > >HashMap原始碼__tableSizeFor方法解析

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的要求了.