HashMap源码逐行分析

        学java的都知道HashMap一向是java基础面试的重点,最近抽时间研究了下jdk1.8的HashMap源码,佩服作者写代码的能力,做了下笔记,希望能对自己之后写代码能借鉴思想,受到启发。

 

HashMap的底层:数组+链表(jdk7及之前)

数组+链表+红黑树(jdk7及之前)

 

jdk1.8源码逐行解读:

 

1.首先new一个HashMap的时候,加载因子loadFactor赋值为0.75,new的时候仅做此操作。

2.put操作,调用putVal方法

putVal方法说明,@1:对key值进行hash操作的结果,@2:key值,@3:value值,@4:如果为true则不更新value值,hashmap用的是false,@5:如果为true表处于创建模式。

 

3,以第一次put操作为例,此时还没有产生任何数据,来看看流程:

①先定义一个Node数组tab,一个Node元素p,int n i;

②判断table是否为空,table是定义的一个Node数组,第一次未作任何操作,所以为空。

③调用resize()方法,该方法注释如下,是说初始化或将table的size*2

resize()方法分析:

①由于是第一次新增,oldTab为null则orderCap=0,orderThr=0

直接跳到②

②newCap会被赋值默认大小16

newThr会被赋值默认size x 加载因子0.75=12;

③临界值threshold赋值为12。

此处创建一个大小为16的数组,并赋值给table

table=new Node[16]

由于oldTab一直为空,所以resize()最终返回一个长度为16的数组。

④此时n=tab.size()为16,i=(15&hash)也就是4个1和key的hash值做与运算,相当于只取低四位,得出tab[i]位置的元素,此时因为是第一次添加tab[i]一定为空,所以直接走newNode方法然后放到tab[i]处。

⑤后续的方法基本都没有什么执行了。hashMap的第一次put完成

4,以后续put操作为例,此时已经存在了一些数据,来看看流程:

①如果已经存在数据了,则直接走①的判断,如果tab[i]不为空,则直接将新元素放置tab[i]处。

②如果tab[i]已经存在了数据,且存在的数据hash值和key的hash值相等,且key值和tab[i]equals为true,将e赋值为tab[i];(即:如果是hash值相等且equals相等则才可以说明是相等。)

③如果不相等,判断tab[i]处元素是否是红黑树,是的话,调用红黑树put的方法。

④开始循环链表,如果下一个元素为空,则newNode到下一个节点。

⑤如果链表的长度>=8了则调用treeifyBin方法

treeifyBin方法分析:

①首先会先判断数组长度是否小于64,如果小于先调用resize()做扩容操作。

②否则将链表转为红黑树(也就是说红黑树必须在链表长度大于8,数组长度小于64才会出现)

⑥继续循环链表,如果下一个元素不为空,且和加入元素相等则跳出。

⑦如果添加的key值存在相等的那么将value替换掉。

⑧afterNodeAccess此函数在HashMap中为空方法。

⑨put操作的最后一步如果本次put有新增元素size++如果大于临界值了,调用resize进行扩容操作。

最后再分析下resize的操作:

①当table不为空时,oldCap>0且oldCap比容器最大值还大的话,直接返回原数组并将临界值置为最大int值。

②当table不为空时,oldCap的两倍还小于容器最大值且oldCap大于容器默认大小16则将容器大小和临界值都扩大两倍。

③当调用带参构造器时会进入改条件。

④初始化时进入该条件。

⑤剩余的操作就是新建一个大小两倍的数组,然后将之前数组中的元素重新计算hash值然后放入。

5,HashMap源码其他部分相关了解

带参构造器:

我们在用  HashMap 的时候,如果用默认构造器,就会建一个初始容量为 16,加载因子为 0.75 的 HashMap。这样做有个缺点,就是在数据量比较大的时候,会进行频繁的扩容操作,扩容会发生数据的移位,为了避免扩容,提高性能,我们习惯预估下容量,然后通过带容量的构造器创建

hash()方法:

首先我们知道 HashMap 在做 put 操作的时候,会先对 key 做 hash 操作,直接定位到源码位置:

这个操作是把 key 的 hashCode 值与 hashCode 值右移 16 位做异或(不同为 1,相同为 0),这样就是把哈希值的高位和低位一起混合计算,这样就能使生成的 hash 值更离散

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值