概述
底层结构
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 方法))(扩容拆分红黑树时遍历的就是这条链表)
最后
以上就是拼搏蓝天为你收集整理的Java HashMap 总结 (1.7/1.8)的全部内容,希望文章能够帮你解决Java HashMap 总结 (1.7/1.8)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复