爲什麼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