🗒️HashMap初始化容量计算

type
status
slug
date
tags
summary
category
password
icon

简单重新认识

Java为数据结构中的映射定义了一个接口java.util.Map,此接口主要有四个常用的实现类,分别是HashMap、Hashtable、LinkedHashMap和TreeMap,类继承关系如下图所示:
notion image
下面针对各个实现类的特点做一些说明:
(1) HashMap:它根据键的hashCode值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的。 HashMap最多只允许一条记录的键为null,允许多条记录的值为null。HashMap非线程安全,即任一时刻可以有多个线程同时写HashMap,可能会导致数据的不一致。如果需要满足线程安全,可以用 Collections的synchronizedMap方法使HashMap具有线程安全的能力,或者使用ConcurrentHashMap。
(2) Hashtable:Hashtable是遗留类,很多映射的常用功能与HashMap类似,不同的是它承自Dictionary类,并且是线程安全的,任一时间只有一个线程能写Hashtable,并发性不如ConcurrentHashMap,因为ConcurrentHashMap引入了分段锁。Hashtable不建议在新代码中使用,不需要线程安全的场合可以用HashMap替换,需要线程安全的场合可以用ConcurrentHashMap替换。
(3) LinkedHashMap:LinkedHashMap是HashMap的一个子类,保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的,也可以在构造时带参数,按照访问次序排序。
(4) TreeMap:TreeMap实现SortedMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator遍历TreeMap时,得到的记录是排过序的。如果使用排序的映射,建议使用TreeMap。在使用TreeMap时,key必须实现Comparable接口或者在构造TreeMap传入自定义的Comparator,否则会在运行时抛出java.lang.ClassCastException类型的异常。
对于上述四种Map类型的类,要求映射中的key是不可变对象。不可变对象是该对象在创建后它的哈希值不会被改变。如果对象的哈希值发生变化,Map对象很可能就定位不到映射的位置了。
通过上面的比较,我们知道了HashMap是Java的Map家族中一个普通成员,鉴于它可以满足大多数场景的使用条件,所以是使用频度最高的一个。下文我们主要结合源码,从存储结构、常用方法分析、扩容以及安全性等方面深入讲解HashMap的工作原理。

扩容

初始状态

  • HashMap默认的初始容量是16,并且要求容量始终为2的幂。
  • 默认的加载因子(load factor)是0.75,这是一个用于确定何时增加容量的比率。
  • 当实际大小超过capacity * load factor时,就会触发扩容操作。

扩容过程

  1. 容量翻倍
      • HashMap的元素数量超过了capacity * load factor时,它会进行扩容。
      • 扩容通常是将容量翻倍,即新的容量为原来的两倍。
      • 新的容量必须是2的幂次方。
  1. 重新散列
      • 扩容后,原有的所有条目都需要重新计算哈希值和索引位置。
      • 这是因为哈希码与数组大小有关,而数组大小已经改变。
      • 重新散列可能会导致原本位于不同桶(bucket)的条目现在位于同一个桶中,或者相反。
  1. 树化
      • 在Java 8中引入了一个额外的优化,当链表长度达到一定阈值(默认为8)时,链表会被转换成红黑树以提高查找效率。
      • 如果在后续操作中某个桶中的元素数量减少到一个阈值以下(默认为6),则该红黑树会被转换回链表。
notion image

初始化容量设置计算公式

(需要存储的元素个数 /负载因子) + 1
还是计算值是2的幂次方(2 4 8 16)向上取

Case

合代码的时候有这种,问题很大吗?其实也就那样子无可厚非了,顺着别人习惯来吧,小细节依旧不不影响别人写牛逼,高性能高可用的代码。

Nacos错误示例使用

2*0.75=1.5
由于元素数量不能是小数,所以它可以容纳 1 个元素而不需要扩容。当您放入第二个元素时,HashMap 中的元素数量就达到了容量的 100%,超过了默认负载因子所允许的阈值

错误示例业务代码

4*0.75 = 3
插入第四个的时候扩容

测试代码

参考

上一篇
Java微服务生态系统构建指南
下一篇
mac arm Java maven等环境安装
Loading...
文章列表
王小扬博客
云原生
Git
Elasticsearch
Apollo
产品
Think
生活技巧
软件开发
计算机网络
CI
DB
设计
缓存
Docker
Node
操作系统
Java
大前端
Nestjs
其他
PHP
AI