hashmap的负载因子为什么是0.75而不是其他值或者1

https://blog.csdn.net/dengbixuan/article/details/104767065

为什么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
 

Guess you like

Origin blog.csdn.net/Maxiao1204/article/details/120443022