Java HashMap 总结 (1.7/1.8)

底层结构

1.7:数组 + 链表
1.8:数组 + 链表 + 红黑树

put 方法流程
1.7
  • 判断数组是否已初始化,没有则进行初始化(容量默认是16,若在构造方法中指定了则为大于等于指定容量的最小 2 的次幂)
  • 计算下标,若 key 为 null 则下标为 0,key 不为 null 时下标为 hash & length - 1,其中 hash 值通过 key.hashCode() 与哈希种子计算得到
  • 调用 addEntry 方法,先判断是否需要扩容,扩容条件为:元素数量(插入前) >= 容量 * 加载因子(默认0.75) 且该下标位置的元素不为 null
  • 创建 Entry 对象放在新下标位置(头插法)
1.8
  • 判断数组是否已初始化,没有则进行初始化(容量默认是16,若在构造方法中指定了则为大于等于指定容量的最小 2 的次幂)
  • 计算下标,若 key 为 null 则下标为 0,key 不为 null 时下标为 hash & length - 1,其中 hash 值为 key.hashCode() 高16位与低16位异或的结果(没有哈希种子的逻辑)
  • 执行插入逻辑(判断下标位置节点的类型):
    • 为 null:直接插入新节点
    • 链表:使用尾插法插入新节点,若插入后链表长度超过 8 且数组长度 >= 64 则进行转红黑树(第二个条件不满足则进行扩容)
    • 红黑树:调用 putTreeVal 方法将节点插入到红黑树中
  • 判断是否需要扩容,扩容条件为:元素数量(插入后) > 容量 * 加载因子(默认0.75)
扩容过程
1.7
  • 创建新数组(长度为原来的 2 倍)
  • 迁移数据
    • 判断是否需要 rehash(与系统参数有关,若不设置则一般为 false)
    • 计算在新数组中的下标,使用头插法插入
1.8
  • 创建新数组(长度为原来的 2 倍)
  • 迁移数据(判断下标位置节点的类型)
    • 单个节点:直接计算新数组中的下标并赋值 (1.8 没有 rehash 的逻辑)
    • 链表:先构造出两条链表(尾插法),再一次性移到新数组 (节点在新数组中的下标只有两种可能,要么和原数组下标相同,要么是 原数组下标 + 原数组长度 )
    • 红黑树:也是按新下标构造两条链表 (但是是双向链表),并移到新数组
      • 链表长度 <= 6:将该链表的节点类型 (TreeNode) 转换为普通链表节点
      • 链表长度 > 6:若另一条链表不为空则需要重新树化 (另一条链表为空则就是原来那棵树整个移过去了)
1.8 链表转红黑树的过程
  • 将链表的节点替换为 TreeNode,形成双向链表
  • 将链表的头节点作为红黑树的根节点,遍历链表,将元素插入到红黑树中 (插入过程中根节点可能会发生变化,链表的头节点也同步地改变 (moveRootToFront 方法))(扩容拆分红黑树时遍历的就是这条链表)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值