HashMap

HashMap的默认初始长度为16,且每次扩展或者手动初始化时,长度必须是2的幂,之所以选择16,是为了服务于从Key映射到Index的Hash算法。

为实现尽量均匀的Hash函数,HashMap采用了位运算的方法。以下为公式

index = HashCode(key) & (Length -1)

采用16的初始长度的最好作用是使得得出的Index结果均匀分布

线程安全

首先HashMap是线程不安全的数据结构,在高并发情况下,容易因为Rehash过程中形成环,而导致后期GET时出现死循环。线程安全的HashMap为ConcurrentHashMap

Rehash是HashMap的Resize(扩展)中的一步,影响Resize的因素有两个,分别是

  1. Capacity容量(当前长度,2的幂)
  2. LoadFactor负载因子(默认为0.75f)

而衡量HashMap是否需要Resize的依据是

HashMap.Size >= Capacity * LoadFactor

HashMap的扩展过程如下

1.扩容

创建一个新的Entry空数组,长度为原数组的两倍

2.Rehash

由于Hash函数 index=HashCode(Key)&(Length -1)

中使用了Length这一长度变量,因此每次扩展都需要全局Rehash

而在Rehash中很容易由于并发问题导致出现链表环

PUT方法

由于HashMap长度有限,当插入的Entry越来越多时,也会出现index冲突的情况,此时应注意到HaspMap的每个元素不仅仅只是一个Entry对象,也是一个链表的头结点,当新的Entry映射到冲突的数组位置时,只需要插入相对应的链表即可。

插入链表的方式使用的是头插法,是因为HashMap发明者任务,后插入的Entry被查找的可能性更大。

GET方法

根据输入的Value值由Hash算法计算出index,然后从对应index的链表中遍历查询。

KAI Java, 容器