HashMap的負載因子初始值爲什麼是0.75?這篇文章以最通俗的方式告訴你答案

之前寫過一篇專門介紹HashMap的文章,反響很不錯,不過在留言區問的最多的問題就是HashMap的負載因子初始值爲什麼是0.75,私下又好好地研究了一番,總結了這篇文章。

本篇文章基於JDK1.8,特在此說明。

OK。下面我們就開始進行分析。

#一、負載因子的作用

對於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衝突,使得底層的鏈表或者是紅黑樹的高度比較低,提升了空間效率。

OK,寫到這答案基本上就出來了,一句話能總結的寫成了一篇文章。如有問題,還請批評指正。

在這裏插入圖片描述

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