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的因素有两个,分别是
- Capacity容量(当前长度,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的链表中遍历查询。