HashMap 的底层实现是什么?
HashMap 的底层实现是哈希表。在 jdk 1.8 之前是数组 + 链表,jdk 1.8 之后是数组 + 链表 + 红黑树。
当向 HashMap 中 put 元素时,会利用 key 的 hashCode 计算出当前元素在数组中的下标。然后将元素放入数组对应的下标位置中。
在存储时,如果数组该位置已经有元素,则判断 key 是否相同。如果 key 相同,则覆盖 value。否则将新元素插入链表或者红黑树中。
当从 HashMap 中获取元素时,直接去数组中找 key 的哈希值对应的下标。再进一步判断 key 是否相同,从而获取对应的值。
HashMap jdk 1.7 和 1.8 的区别:
- 1.7 使用数组 + 链表。是头插法。
- 1.8 使用数组 + 链表 + 红黑树。是尾插法。当链表长度大于 8、数组长度大于等于 64 时,会转化为红黑树。
解决Hash冲突的方法有哪些?HashMap 是如何解决 Hash 冲突的?
解决 Hash 冲突的方法有:
- 链地址法:在数组的每个位置维护一个链表。把冲突的元素放在链表的尾部。
- 开放寻址法:通过某种探测算法,在哈希表中寻找下一个空闲位置存储元素。
HashMap 采用链地址法。
HashMap 的 put 方法流程?
- 判断 HashMap 中的数组长度是否为 0 或者 null,是的话就要执行 resize() 方法进行初始化。
- 计算要插入的元素的 key 的哈希值得到数组索引,检查数组对应位置上是否已经有元素。如果没有元素,直接把要插入的元素放到这个位置。
- 如果已经有元素,则检查数组对应位置的第一个元素的 key 是否与要插入的元素的 key 相同,如果相同则直接覆盖 value。
- 如果不相同,则需要遍历链表或者红黑树。遍历过程中如果发现 key 相同则直接覆盖 value。否则在尾部插入。对于链表,如果发现链表长度大于 8,数组长度大于等于 64,还会将链表转换为红黑树。
- 插入完毕后,检查 HashMap 的元素个数是否大于扩容阈值,如果大于,需要再对 HashMap 进行扩容。
HashMap 的扩容机制?
- 生成新数组,长度为旧数组 2 倍。
- 遍历旧数组每个位置上的链表或红黑树。
- 如果是链表,则直接计算链表中每个元素在新数组长度下的下标,并将它们拷贝到新数组对应位置中去。
- 如果是红黑树,则先遍历红黑树,计算红黑树中每个元素在新数组下的下标。
- 统计新数组每个位置元素个数。
- 如果大于 8,则生成一个红黑树,按红黑树的方式插入元素。
- 如果小于 8,则说明红黑树会退化为链表,则生成一个链表,按链表的方式插入元素。
- 转移完毕后,将新数组的引用赋值给 HashMap 的 table 属性。
4101

被折叠的 条评论
为什么被折叠?



