put方法主要干这几件事情:
1.算出key的hash值,key的hashcode的高低位异或算出来。
2.若果散列表为空,则初始化散列表。
3.算出散列表下标位置,(n - 1) & hash。
4.散列表下标位置值为空,则把传入的参数封装成node节点设置到散列表下标位置。
5.如果该散列表下标的值不为空,如果key和hash值与传入的值相等,则直接覆盖,如果散列表下标的节点是红黑树,则走红黑树的逻辑,相等则覆盖,不相等,则插入,具体红黑树逻辑后面会讲解。
6.如果当前散列表下标的值与传入的值不相等,又不是红黑树,则判断该下标的节点next是否为空,如果为空直接把传入的参数封装成node节点插入到该散列表下标值后面,然后判断链表元素个数是否超过8,超过则走树化的逻辑,没超过则break,修改次数modCount加1,元素个数加1,然后判断散列表元素个数是否超过扩容阈值,超过则扩容。
7.如果是链表,已经发生过hash冲突了,则循环这个链表,key,hash值相等则覆盖,不相等则插入,插入完以后再次判断是否达到树化条件,没有达到树化条件,break,修改次数modCount加1,元素个数加1,然后判断散列表元素个数是否超过扩容阈值,超过则扩容.

 下面看具体的源码。

1.put方法入口如下图所示,先算key的hash值,再调用putVal方法进行put操作。

2.看下hash(key)方法。key的hashcode,高低位异或运算。key==null 返回0,说明null是插入在散列表下标第0个位置。

3.得到完key的hash以后返回进入putVal方法。该方法主要就是处理散列表初始化,key,value的插入覆盖,但分链表,红黑树,和没有hash冲突的情况。下面一个一个看吧。首先刚进入该方法,我们要判断一下该散列表是否为null或者散列表的length是否等于0,如果是则调用resize初始化散列表。具体resize初始化逻辑,可以看下上一篇文章。散列表不为空,算出散列表下标位置((n - 1) & hash),如果该下标位置node节点为null,则把参数封装成node节点插入该下标位置。

4.如果该散列表下标的值不为空。那么就先判断与传入的hash,key是否相等,如果相等则覆盖,如果不相等,则判断该下标元素node是否是红黑树,如果是红黑树则走红黑树的逻辑(红黑树后面单独讲),如果不满足红黑树的条件,那就是链表的场景了。

看下链表的场景,如果该散列表下标node的next为空,则把传入的参数封装成node,设到该下标node的后面。设完以后,判断是否达到树化条件,达到了就树化,break跳出循环,修改次数加1,散列表元素个数size加1.接着如果是本来已经有hash冲突的情况,则链表已经生成,循环该链表,如果key,hash相等则覆盖,不相等则插入,插入完一样判断树化条件,修改次数加1,散列表元素个数size加1,然后判断散列表元素个数是否超过扩容阈值,超过则扩容。

 

posted on 2021-02-08 09:58  路飞_lufei  阅读(122)  评论(1编辑  收藏  举报