HashMap的負載因子初始值爲什麼是0.75?

注:本片文章基於JDK1.8,特在此說明。

一、首先介紹下負載因子的作用

對於HashMap的研究,我之前一直停留在烤爐源碼的實現,其實現在看來,系統默認的各種參數纔是HashMap的精華所在。

負載因子是和擴容機制有關的,意思時如果當前容器的容量達到了我們設定的最大值,就要開始執行擴容操作。舉例說明下

比如說當前的容器容量是16,負載因子是0.75,16*0.75=12,也就是說,當容量達到了12的時候就會進行擴容操作

他的作用很簡單,相當於是一個擴容機制的閾值。當超過了這個閾值,就會觸發擴容機制。HashMap源碼已經爲我們默認指定了負載因子是0.75。

public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable {
    //略
    static final float DEFAULT_LOAD_FACTOR = 0.75f;
    //略
    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);
    }
    //略
}

我截取了部分源碼,從這裏可以看出,系統默認的負載因子值就是0.75,而且我們還可以在構造方法中去指定。下面我們就正式來分析一下爲什麼是默認的0.75。

二、原因解釋
我們在考慮HashMap的時候,首先要想到的是HashMap只是一個數據結構,既然是數據結構最主要的就是節省時間和空間。負載因子的作用肯定也是節省時間和空間。因爲是什麼呢?首先我們考慮下兩種極端情況。

1、負載因子是1.0
首先看下HashMap的底層數據結構

在這裏插入圖片描述
我們的數據一開始是保存在數組裏面的,當發生了Hash碰撞的時候,就是在這個數據節點上,生出一個鏈表,當鏈表長度達到一定長度的時候,就會把鏈表轉化爲紅黑樹。

當負載因子是1.0的時候,也就意味着,只有當數組的8個值(這個圖表示了8個)全部填充了,纔會發生擴容。這就帶來了很大的問題,因爲Hash衝突時避免不了的。當負載因子是1.0的時候,意味着會出現大量的Hash的衝突,底層的紅黑樹變得異常複雜。對於查詢效率極其不利。這種情況就是犧牲了時間來保證空間的利用率。

因此一句話總結就是負載因子過大,雖然空間利用率上去了,但是時間效率降低了。

2、負載因子是0.5
負載因子是0.5的時候,這也就意味着,當數組中的元素達到了一半就開始擴容,既然填充的元素少了,Hash衝突也會減少,那麼底層的鏈表長度或者是紅黑樹的高度就會降低。查詢效率就會增加。

但是,兄弟們,這時候空間利用率就會大大的降低,原本存儲1M的數據,現在就意味着需要2M的空間。

一句話總結就是負載因子太小,雖然時間效率提升了,但是空間利用率降低了。

3、負載因子0.75
經過前面的分析,基本上爲什麼是0.75的答案也就出來了,這是時間和空間的權衡。答案就在源碼上,我們可以看看:

/* <p>As a general rule, the default load factor (.75) offers a good
 * tradeoff between time and space costs.  Higher values decrease the
 * space overhead but increase the lookup cost (reflected in most of
 * the operations of the <tt>HashMap</tt> class, including
 * <tt>get</tt> and <tt>put</tt>).  The expected number of entries in
 * the map and its load factor should be taken into account when
 * setting its initial capacity, so as to minimize the number of
 * rehash operations.  If the initial capacity is greater than the
 * maximum number of entries divided by the load factor, no rehash
 * operations will ever occur.*/

大致意思就是說負載因子是0.75的時候,空間利用率比較高,而且避免了相當多的Hash衝突,使得底層的鏈表或者是紅黑樹的高度比較低,提升了空間效率。

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