HashMap的負載因子爲什麼不設置成1

爲什麼HashMap的負載因子設置成0.75,而不是1也不是0.5?這背後到底有什麼考慮?

在HashMap源碼中 HashMap默認容量大小是16,最大容量是2的30次方,默認的負載因子是0.75f;

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

static final int MAXIMUM_CAPACITY = 1 << 30;

static final float DEFAULT_LOAD_FACTOR = 0.75f;

1. 什麼是負載因子?

     負載因子(loadFactor)表示HashMap滿的程度,默認值爲0.75f,也就是說默認情況下,當HashMap中元素個數達到了容量的3/4的時候就會進行自動擴容。

     第一次創建HashMap的時候,就會指定其容量(如果未明確指定,默認是16)。隨着我們不斷的向HashMap中put元素的時候,就有可能會超過一定的閾值,那麼就需要有一個擴容機制。所謂擴容,就是擴大HashMap的容量(JDK1.8):

        final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
        .......
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

從代碼中我們可以看到,在向HashMap中添加元素過程中,如果 元素個數(size)超過臨界值(threshold) 的時候,就會進行自動擴容(resize),並且,在擴容之後,還需要對HashMap中原有元素進行rehash,即將原來桶中的元素重新分配到新的桶中。

     在HashMap中,臨界值(threshold) = 負載因子(loadFactor) * 容量(capacity)。

2. 爲什麼要擴容?

    HashMap在擴容到過程中不僅要對其容量進行擴充,還需要進行rehash!所以,這個過程其實是很耗時的,並且Map中元素越多越耗時。rehash的過程相當於對其中所有的元素重新做一遍hash,重新計算要分配到那個桶中。

    HashMap 是一個數組加鏈表的結構,不擴容也是可以無限存儲的,爲什麼要擴容?

    擴容是爲解決哈希衝突問題。HashMap其實是底層基於哈希函數實現的,但是哈希函數都有如下一個基本特性:根據同一哈希函數計算出的哈希值如果不同,那麼輸入值肯定也不同。但是,根據同一哈希函數計算出的哈希值如果相同,輸入值不一定相同。兩個不同的輸入值,根據同一哈希函數計算出的哈希值相同的現象叫做碰撞。

   HashMap將數組和鏈表(或者紅黑樹)組合在一起,發揮了兩者的優勢,我們可以將其理解爲鏈表的數組。但是,如果一個HashMap中衝突太高,那麼數組的鏈表就會退化爲鏈表。這時候查詢速度會大大降低。

    爲了解決哈希衝突問題,在合適的時候擴大數組容量,再通過一個合適的hash算法計算元素分配到哪個數組中,就可以大大的減少衝突的概率。就能避免查詢效率低下的問題。

3.爲什麼默認loadFactor是0.75?

   爲了避免哈希碰撞,HashMap需要在合適的時候進行擴容。那就是當其中的元素個數達到臨界值的時候,而這個臨界值前面說過和loadFactor有關,換句話說,設置一個合理的loadFactor,可以有效的避免哈希衝突。

  關於loadFactor在JDK官方文檔裏有說明:一般來說,默認的負載因子(0.75)在時間和空間成本之間提供了很好的權衡。更高的值減少了空間開銷,但增加了查找成本(反映在HashMap類的大多數操作中,包括get和put)。

  試想一下,如果我們把負載因子設置成1,容量使用默認初始值16,那麼表示一個HashMap需要在"滿了"之後纔會進行擴容。那麼在HashMap中,最好的情況是這16個元素通過hash算法之後分別落到了16個不同的桶中,否則就必然發生哈希碰撞。而且隨着元素越多,哈希碰撞的概率越大,查找速度也會越低。

  如果負載因子設置爲0.5,那麼就會頻繁的擴容,浪費空間。

  loadFactor=0.75科學依據

 a .根據數學公式推算。負載因子爲log(2)的時候,可以既減少哈希衝突,又浪費空間,是時間和空間的權衡。

    log(2)大約爲0.7。

 b.根據HashMap的擴容機制,應該保證capacity的值永遠都是2的冪。

    爲了保證負載因子(loadFactor) * 容量(capacity)的結果是一個整數,這個值是0.75(3/4)比較合理,因爲這個數和任何2的冪乘積結果都是整數。

  參考:https://mp.weixin.qq.com/s/_zbOHbQa2zDVosXUlYUrSQ

 

 

   

 

 

 

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