1.基本数据结构

  1. JDK1.7 数组 + 链表

  2. JDK1.8 数组 + (链表 | 红黑树)

2.树化与退化

  1.树化意义

    1.红黑树用来避免Dos攻击,防止链表过长时性能下降,树化应该是偶然情况,是保底策略.

    2.hash 表的查找,更新的时间复杂度是 O(1),而红黑树的查找,更新的时间复杂度是 O(log2⁡n ),TreeNode 占用空间也比普通 Node 的大,如非必要,尽量还是使用链表

    3.hash 值如果足够随机,则在 hash 表内按泊松分布,在负载因子 0.75 的情况下,长度超过 8 的链表出现概率是 0.00000006,树化阈值选择 8 就是为了让树化几率足够小

  2.树化规则

    1.当链表长度超过树化阈值8时,先尝试扩容来减少链表长度,如果数组容量已经 >= 64,才会进行树化.

  3.退化规则

    1. 情况1:在扩容时如果拆分树时,树元素 <= 6 则会退化链表

    2. 情况2:在 remove 树节点时若 root 根节点,根节点的左右子节点或者孙节点只要有一个为 null 也会退化为链表.

3.索引计算

  1.索引计算方法

    1.首先,计算对象的hashCode()

    2.再进行调用HashMap的hash()方法进行二次哈希 (二次哈希是为了综合高位数据,让哈希分布更为均匀)

    3.最后 哈希结果 & (数组容量 - 1) 得到索引位置

  2.数组容量为何是2的 n 次幂

    1.计算索引时,如果是2的n次幂可以使用位于运算替代取模,效率更高.

    2.扩容时 hash & 旧容量 == 0的元素留在原来位置,否则新位置 = 旧位置 + 旧容量

    3.上述都是为了配合容量为2的 n 次幂时的优化手段,例如 HashTable的容量就不是2的 n 次幂,并不能说哪种设计更好.

4. put 与 扩容

  1. put 流程

    1.HashMap 是懒惰创建数组的,首次使用才创建数组

    2.计算索引(桶下标)

    3.如果桶下标还没人占用,创建 Node 占位返回

    4.如果桶下标已经有人占用

      1.已经是 TreeNode 走红黑树的添加或更新逻辑

      2.是普通 Node,走链表的添加或更新逻辑,如果链表长度超过树化阈值,走树化逻辑

    5.返回前检查容量是否超过阈值,一旦超过进行扩容

  2. 1.7 与 1.8 的区别

    1. 表插入节点时,1.7是头插法,1.8是尾插法

    2. 1.7是大于等于阈值且没有空位时才扩容,而1.8是大于阈值就扩容

    3. 1.8在扩容计算Node索引时会优化

  3. 扩容加载因子 (factor) 为何默认是0.75f

    1. 在空间占用和查询时间之间取得比较好的权衡

    2. 大于这个值,空间节省了,但是链表就会比较长,影响性能

    3. 小于这个值,冲突减少了,但是扩容更频繁,空间占用更多

5.并发问题

  1.扩容死链 (1.7会存在)

    1.7 源码如下:

void transfer(Entry[] newTable, boolean rehash) {
int newCapacity = newTable.length;
for (Entry<K,V> e : table) {
while(null != e) {
Entry<K,V> next = e.next;
if (rehash) {
e.hash = null == e.key ? 0 : hash(e.key);
}
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
}
}
}
  • e 和 next 都是局部变量,用来指向当前节点和下一个节点

  • 线程1(绿色)的临时变量 e 和 next 刚引用了这俩节点,还未来得及移动节点,发生了线程切换,由线程2(蓝色)完成扩容和迁移

    线程2 扩容完成,由于头插法,链表顺序颠倒。但线程1 的临时变量 e 和 next 还引用了这俩节点,还要再来一遍迁移

    第一次循环

    • 循环接着线程切换前运行,注意此时 e 指向的是节点 a,next 指向的是节点 b

    • e 头插 a 节点,注意图中画了两份 a 节点,但事实上只有一个(为了不让箭头特别乱画了两份)

    • 当循环结束是 e 会指向 next 也就是 b 节点

    • 第二次循环

      • next 指向了节点 a

      • e 头插节点 b

      • 当循环结束时,e 指向 next 也就是节点 a

      第三次循环

      • next 指向了 null

      • e 头插节点 a,a 的 next 指向了 b(之前 a.next 一直是 null),b 的 next 指向 a,死链已成

      • 当循环结束时,e 指向 next 也就是 null,因此第四次循环时会正常退出

HashMap知识点的更多相关文章

  1. HashMap知识点总结,这一篇算是总结的不错的了,建议看看!

    HashMap存储结构 内部包含了⼀个 Entry 类型的数组 Entry[] table.transient Entry[] table;(transient:表示不能被序列化)Entry类型存储着 ...

  2. HashMap知识点、问题

    转载:https://blog.csdn.net/qq_27007251/article/details/71403647 https://www.cnblogs.com/kxdblog/p/4323 ...

  3. 阿里P7岗位面试,面试官问我:为什么HashMap底层树化标准的元素个数是8

    前言 先声明一下,本文有点标题党了,像我这样的菜鸡何德何能去面试阿里的P7岗啊,不过,这确实是阿里p7级岗位的面试题,当然,参加面试的人不是我,而是我部门的一个大佬.他把自己的面试经验分享给了我,也让 ...

  4. 牛客网Java刷题知识点之为什么HashMap和HashSet区别

    不多说,直接上干货! HashMap  和  HashSet的区别是Java面试中最常被问到的问题.如果没有涉及到Collection框架以及多线程的面试,可以说是不完整.而Collection框架的 ...

  5. 牛客网Java刷题知识点之为什么HashMap不支持线程的同步,不是线程安全的?如何实现HashMap的同步?

    不多说,直接上干货! 这篇我是从整体出发去写的. 牛客网Java刷题知识点之Java 集合框架的构成.集合框架中的迭代器Iterator.集合框架中的集合接口Collection(List和Set). ...

  6. 牛客网Java刷题知识点之Map的两种取值方式keySet和entrySet、HashMap 、Hashtable、TreeMap、LinkedHashMap、ConcurrentHashMap 、WeakHashMap

    不多说,直接上干货! 这篇我是从整体出发去写的. 牛客网Java刷题知识点之Java 集合框架的构成.集合框架中的迭代器Iterator.集合框架中的集合接口Collection(List和Set). ...

  7. 牛客网Java刷题知识点之HashMap的实现原理、HashMap的存储结构、HashMap在JDK1.6、JDK1.7、JDK1.8之间的差异以及带来的性能影响

    不多说,直接上干货! 福利 => 每天都推送 欢迎大家,关注微信扫码并加入我的4个微信公众号:   大数据躺过的坑      Java从入门到架构师      人工智能躺过的坑          ...

  8. HashMap面试知识点

    HashMap的工作原理是近年来常见的Java面试题. 几乎每个Java程序员都知道HashMap,都知道哪里要用HashMap,知道Hashtable和HashMap之间的区别,那么为何这道面试题如 ...

  9. HashMap面试知识点总结

    主要参考 JavaGuide 和 敖丙 的文章, 其中也有参考其他的文章, 但忘记保存链接了, 文中图片也是引用别的大佬的, 请见谅. 新手上路, 若有问题, 欢迎指正. 背景 HashMap 的相关 ...

  10. HashMap几个需要注意的知识点

    HashMap简介 HashMap 是java集合框架的一部分. key value都允许null值 (除了非同步和允许使用 null 之外,HashMap 类与 Hashtable 大致相同) 不保 ...

随机推荐

  1. 阿里云免费SSL证书申请全过程(图文详解)

    下面我们来详细说下阿里云的域名是如何注册购买,解析绑定的. 首先,打开阿里云官网 ​万网早就被阿里云收购了,所以是同一家.输入你想购买的域名,我这里是随便输入了"aliyun.com&quo ...

  2. SSH通过本地开端口打远程隧道

    ssh -R 你想让别人连得端口:带外IP:22 root@内网跳板机 -p内网跳板机端口 例如: ssh -R 8888:172.22.200.1:22 root@10.11.11.11 -p202 ...

  3. Docker for the Virtualization Admin

    Docker is one of the most successful open source projects in recent history, and organizations of al ...

  4. WebUI自动化框架-playwright

    (持续更新) 一.环境准备 安装playwright:playwright是基于python3.7开发的第三方包,所以需要使用的python版本是3.7及其以上的 pip install playwr ...

  5. Gradio 和 Streamlit 安装与使用教程

    最近 Sealos Devbox 有点火 ,越来越多的小伙伴都开始使用 Sealos Devbox,有位小伙伴写的文章阅读量已经接近了两万! 评论区有个小伙伴问我能不能出一篇部署 Gradio 和 S ...

  6. CSP2023总结

    CSP2023总结 入门组 比赛开始时,顺序开题. 看完 \(T1\) 后没有立即想出正确解法,有点慌乱,看完 \(T2,T3\) 并思考了一会后过去了大概 \(20\) 分钟,想到了解法便看 \(T ...

  7. AI运动小程序开发常见问题集锦二

    截止到现在写博文时,我们的AI运动识别小程序插件已经迭代了23个版本,成功应用于健身.体育.体测.AR互动等场景:为了让正在集成或者计划进行功能扩展优化的用户,少走弯路.投入更少的开发资源,针对近期的 ...

  8. php yield使用

    在循环一个大数组的时候yield非常好用能节省内存. 比如有个大文件需要读取并处理,如果全部读出来太耗费内存,就可以这样做 <?php function getRows($file) { $ha ...

  9. 静态分析工具及使用总结(二)CheckStyle

    这里主要介绍三种开源的工具,PMD.CheckStyle和FindBugs,着重是在Ant里的调用,据说商业软件JTest也是著名的代码分析工具,哈哈,要花钱的没有用过. Checkstyle (ht ...

  10. Docker之基础(一)

    接触Docker有很久一段时间, 但是没有好好总结一下, 借此公司项目全面容器化, 记录一下常用的Docker操作 概况: 本次容器化的项目包括PHP+Python项目,PHP是基于php-fpm的基 ...