HashMap的最大容量爲什麼是2的30次方

HashMap默認容量

看過HashMap源代碼的同學都知道,HashMap有默認的最小容量和最大容量,最小容量是16,最大容量是2的30次方。

    /**
     * 默認的初始化容量-必須是2的冪
     */
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

    /**
     * 最大容量,如果任意帶參構造函數傳入的值大於該數 ,那麼替換成該數。
     * 必須是2的冪,小於等於2~30
     */
    static final int MAXIMUM_CAPACITY = 1 << 30;

爲什麼不是2的31次方?

由於int類型限制了該變量的長度爲4個字節共32個二進制位,按理說可以向左移動31位即2的31次冪,這裏爲什麼不是2的31次方,而是2的30次方呢?
事實上由於二進制數字中最高的一位也就是最左邊的一位是符號位,用來表示正負之分(0爲正,1爲負),所以只能向左移動30位,而不能移動到處在最高位的符號位,所以最大容量只能是2的30次方。

    public static void main(String[] args) {
        System.out.println(1<<30);
        System.out.println(1<<31);
        System.out.println(1<<32);
        System.out.println(1<<33);
        System.out.println(1<<34);

    }

輸出結果:

1073741824
-2147483648
1
2
4

爲什麼要滿足2的n次方

至於爲什麼是2的30次方,不是別的數字或者最大整數,這主要是從性能和分佈均勻兩方面來考慮的:

  • 加快hash計算速度;
  • 均勻分佈,減少hash衝突;

2的n次方,可以通過位移操作來實現,可以加快hash計算速度,結合按位與計算加快數組下標的計算。例如在HashMap做擴容時,滿足2的冪就是相當於每次擴容都是翻倍(就是<<1右移一位),這樣擴容時在重新計算下標位置時,只有兩種情況,一種是下標不變,另一種是下標變爲:原下標位置+擴容前容量,這樣擴容後節點移動相對較少,也可以提高性能。。

可以改善數據的均勻分佈,減少hash衝突,畢竟hash衝突越大,代表數組中一個鏈的長度越大,這樣的話會降低hashmap的性能。
其中關鍵代碼爲HashMap中的數組下標計算:i = (n - 1) & hash,該計算方法可以實現一個均勻分佈。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章