HashMap源码解析

HashMap是一个利用哈希表原理来存储元素的集合。遇到冲突时,HashMao是采用的链地址法来解决,在JDK1.8中,HashMap是由 数组+链表+红黑树构成,新增了红黑树作为底层数据结构,结构变复杂了,但是效率也变的更高了

1、HashMap定义

该类实现了Map接口、Cloneable接口、Serializable接口,继承了AbstractMap抽象类,在Map接口中定义了一组键值对映射通用的操作。

2、字段属性

后面三个字段是JDK1.8新增的,主要是用来进行红黑树和链表的互相转换。

  • Node<K,V>[] table

上面说过HashMap是由数组+链表+红黑树组成,这里的数组就是table字段,后面对其进行初始化长度默认是DEFAULT_INITIAL_CAPACITY= 16

  • Size

集合中存放key-value的实时对数

  • loadFactor

装载因子,用来衡量HashMap满的程度,计算HashMap的实时装载因子的方法为:size/capacity,而不是占用桶的数量去除以capacity。Capacity是桶的数量,也就是table的长度

  • Threshold

计算公式:capacity * loadFactor。这个值是当前已占用数组长度的最大值。过这个数目就重新resize(扩容),扩容后的 HashMap 容量是之前容量的两倍

3、构造函数

①、默认无参构造函数

 

②、指定初始容量的构造函数

 

这段代码的目的是把n的二进制数中的0置为1,比如2是10经过处理后变成11。

4、确定哈希桶数组索引位置

HashMap是数组+链表+红黑树的组合,我们希望在有限个数组位置时,尽量每个位置的元素只有一个,那么当我们用散列函数求得索引位置的时候,我们能马上知道对应位置的元素是不是我们想要的,而不是进行链表的遍历或者红黑树的遍历,HashMap中的哈希算法:

这里获取hashCode()方法的值是变量,因为bucket数组大小是2的幂,计算下标index = (table.length - 1) & hash,如果不做hash处理,相当于散列生效的只有几个低 bit 位。hash方法实际是让key.hashCode()与key.hashCode()>>>16进行异或操作,高16位不变,低16位和高16位做了一个异或处理,目的是减少碰撞。

 

5、添加元素

①、判断键值对数组 table 是否为空或为null,否则执行resize()进行扩容;

②、根据键值key计算hash值得到插入的数组索引i,如果table[i]==null,直接新建节点添加,转向⑥,如果table[i]不为空,转向③;

③、判断table[i]的首个元素是否和key一样,如果相同直接覆盖value,否则转向④,这里的相同指的是hashCode以及equals;

④、判断table[i] 是否为treeNode,即table[i] 是否是红黑树,如果是红黑树,则直接在树中插入键值对,否则转向⑤;

⑤、遍历table[i],判断链表长度是否大于8,大于8的话把链表转换为红黑树,在红黑树中执行插入操作,否则进行链表的插入操作;遍历过程中若发现key已经存在直接覆盖value即可;

⑥、插入成功后,判断实际存在的键值对数量size是否超过了最大容量threshold,如果超过,进行扩容。

⑦、如果新插入的key不存在,则返回null,如果新插入的key存在,则返回原key对应的value值(注意新插入的value会覆盖原value值)

6、扩容机制

当集合是由数组+链表+红黑树构成,向HashMap中插入元素时,如果HashMap集合的元素已经大于了最大承载容量threshold(capacity*loadFactor),这里的threshold不是数组的最大长度,但Java中数组无法自动扩容的,所以采用的方法是用一个更大的数组代替这个小的数组。

该方法分为两个部分,首先是计算新桶数组的容量newCap和新阙值newThr,然后将原集合的元素重新映射到新集合中。

前半部分:计算新桶数组的容量newCap和新阙值newThr

后半部分:将原集合的元素重新映射到新集合中。JDK1.8使用的是2次幂的扩展(指长度扩展为原来的2倍),所以,元素的位置要么在原位置上,要么是在原位置再移动2次幂的位置。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值