HashMap之put详解(一)

本文详细解析了HashMap的put操作,包括源码分析、红黑树的插入处理以及链表转红黑树的过程。在HashMap的put过程中,首次插入会初始化table,然后判断插入位置,如果是红黑树则进行红黑树插入;如果链表达到一定长度,会将链表转换为红黑树。红黑树插入涉及节点遍历、插入位置判断以及插入后的平衡调整。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 导读

这次的分享是关于HashMap::put, 主要是围绕下面几个方面展开:
.1 HashMap::put源码解析;
.2 红黑树插入的处理;
.3 红黑树与链表的互转;

2. HashMap::put源码解析

因为HashMap::put的源码较长, 用下面的流程图来替代:

下面我们一步步来分析:
.1 因为HashMap在初始化的时候, 没有初始化table, 所以在第一次插入时需要初始化table;
.2 判断table[(n - 1) & hash]是否为空, 如果为空则证明是首节点, 直接插入即可;
.3 若不为空, 则需判断挂载的是链表还是红黑树, 若是红黑树, 则走红黑树的插入;
.5 遍历链表, 如果key相同且hash相同, 则直接退出循环;
.6 如果已经到了尾节点, 则直接插入, 再判断链表的长度是否大于8; 若大于8需要转成红黑树;
.7 退出循环后再判断相同key能否覆盖, 能覆盖时直接覆盖, 并返回结果;
.8 插入完成后再判断HashMap.size 是否大于 threshold; 为真时需要扩容;
.9 HashMap::put正常插入的返回结果都为null;
.10 HashMap::put流程中的afterNodeAccess(), afterNodeInsertion()无需关注, 这是LinkedHashMap的处理;

HashMap::put的主流程还是比较清晰的, 但是在JAVA8以后加入了红黑树的处理, 我们需要关注下红黑树的插入与链表转红黑树的操作;

3. 红黑树的插入

HashMap.TreeNode::putTreeVal是红黑树插入的主逻辑:

.1 从根节点遍历槽点的红黑树;
.2 判断待插入节点位于左子树还是右子树, key相等时直接返回, 由主流程判断是否更新节点值;
.3 当遍历到当前节点的左(右)子节点为空时, 插入待插入节点;
.4 再次平衡红黑树;

判断节点位于左右子树的过程在前面的HashMap::get中已经详细的讲解过了, 先比较hash再比较key是否实现了Comparable接口;如果不实现时, 调用HashMap.TreeNode::tieBreakOrder, 我们来看下tieBreakOrder方法做了什么:
tie bread在网球比赛中叫做平局决胜, 如果把判断节点位于那颗子树作为比赛的话:
.1 比较节点的hash值是第一轮;
.2 通过Comparable比较是第二轮;
.3 如果前面两轮没有分出结果, 那么tieBreakOrder就作为决胜轮来比较出一个结果;
.4 当然如果key没有实现Comparable接口, 那么第一轮没结果就会直接进入决胜轮;
我们来看下作为决胜轮的tieBreakOrder方法是如何做到必定出结果的:

    static int tieBreakOrder(Object a, Object b) {
   
   
            int d;
            if (
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值