【校招VIP】Java HashMap 总结 (1.7/1.8)

08月04日 收藏 0 评论 0 java开发

【校招VIP】Java HashMap 总结 (1.7/1.8)

转载声明:文章来源:https://blog.csdn.net/z_s_b_/article/details/125008926

底层结构

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 方法))(扩容拆分红黑树时遍历的就是这条链表)

C 0条回复 评论

帖子还没人回复快来抢沙发