点击上方 "程序员小乐"关注, 星标或置顶一起成长

每天凌晨00点00分, 第一时间与你相约

每日英文

Sometimes you play a game even when you know you're gonna lose. Or sometimes you leave a game even when you know you can win.

有时候,就算知道自己会输,你还是会玩这个游戏。或者有时候,就算知道自己会赢,也会放弃这个游戏。

每日掏心

人生没有机会重来,没有暂停继续。凡事三思而后行,但若做了,就不要后悔,路是自己选的,事是自己做的,一旦后悔,必将击败自信。

来自:依本多情 | 责编:乐乐

链接:blog.csdn.net/qq_36520235/article/details/82417949

程序员小乐(ID:study_tech)第 792 次推文   图片来自百度

往日回顾:程序员加班突发晕厥,领导提醒:一定要保证5个小时睡眠

     

   正文   


一、真实面试题之:Hashmap的结构,1.7和1.8有哪些区别

不同点:

(1)JDK1.7用的是头插法,而JDK1.8及之后使用的都是尾插法,那么他们为什么要这样做呢?因为JDK1.7是用单链表进行的纵向延伸,当采用头插法时会容易出现逆序且环形链表死循环问题。但是在JDK1.8之后是因为加入了红黑树使用尾插法,能够避免出现逆序且链表死循环的问题。

(2)扩容后数据存储位置的计算方式也不一样:

  • 在JDK1.7的时候是直接用hash值和需要扩容的二进制数进行&(这里就是为什么扩容的时候为啥一定必须是2的多少次幂的原因所在,因为如果只有2的n次幂的情况时最后一位二进制数才一定是1,这样能最大程度减少hash碰撞)(hash值 & length-1)

  • 而在JDK1.8的时候直接用了JDK1.7的时候计算的规律,也就是扩容前的原始位置+扩容的大小值=JDK1.8的计算方式,而不再是JDK1.7的那种异或的方法。但是这种方式就相当于只需要判断Hash值的新增参与运算的位是0还是1就直接迅速计算出了扩容后的储存方式。

在计算hash值的时候,JDK1.7用了9次扰动处理=4次位运算+5次异或,而JDK1.8只用了2次扰动处理=1次位运算+1次异或。

扩容流程对比图:

(3)JDK1.7的时候使用的是数组+ 单链表的数据结构。但是在JDK1.8及之后时,使用的是数组+链表+红黑树的数据结构(当链表的深度达到8的时候,也就是默认阈值,就会自动扩容把链表转成红黑树的数据结构来把时间复杂度从O(n)变成O(logN)提高了效率)

这里再进行补充两个问题:

(1)为什么在JDK1.7的时候是先进行扩容后进行插入,而在JDK1.8的时候则是先插入后进行扩容的呢?

//其实就是当这个Map中实际插入的键值对的值的大小如果大于这个默认的阈值的时候(初始是16*0.75=12)的时候才会触发扩容,
//这个是在JDK1.8中的先插入后扩容
if (++size > threshold)resize();

其实这个问题也是JDK8对HashMap中,主要是因为对链表转为红黑树进行的优化,因为你插入这个节点的时候有可能是普通链表节点,也有可能是红黑树节点,但是为什么1.8之后HashMap变为先插入后扩容的原因,我也有点不是很理解?欢迎来讨论这个问题?

但是在JDK1.7中的话,是先进行扩容后进行插入的,就是当你发现你插入的桶是不是为空,如果不为空说明存在值就发生了hash冲突,那么就必须得扩容,但是如果不发生Hash冲突的话,说明当前桶是空的(后面并没有挂有链表),那就等到下一次发生Hash冲突的时候在进行扩容,但是当如果以后都没有发生hash冲突产生,那么就不会进行扩容了,减少了一次无用扩容,也减少了内存的使用

void addEntry(int hash, K key, V value, int bucketIndex) {//这里当钱数组如果大于等于12(假如)阈值的话,并且当前的数组的Entry数组还不能为空的时候就扩容if ((size >= threshold) && (null != table[bucketIndex])) {//扩容数组,比较耗时resize(2 * table.length);hash = (null != key) ? hash(key) : 0;bucketIndex = indexFor(hash, table.length);}createEntry(hash, key, value, bucketIndex);}void createEntry(int hash, K key, V value, int bucketIndex) {Entry<K,V> e = table[bucketIndex];//把新加的放在原先在的前面,原先的是e,现在的是new,next指向etable[bucketIndex] = new Entry<>(hash, key, value, e);//假设现在是newsize++;}

(2)为什么在JDK1.8中进行对HashMap优化的时候,把链表转化为红黑树的阈值是8,而不是7或者不是20呢(面试蘑菇街问过)?

如果选择6和8(如果链表小于等于6树还原转为链表,大于等于8转为树),中间有个差值7可以有效防止链表和树频繁转换。假设一下,如果设计成链表个数超过8则链表转换成树结构,链表个数小于8则树结构转换成链表,如果一个HashMap不停的插入、删除元素,链表个数在8左右徘徊,就会频繁的发生树转链表、链表转树,效率会很低。

还有一点重要的就是由于treenodes的大小大约是常规节点的两倍,因此我们仅在容器包含足够的节点以保证使用时才使用它们,当它们变得太小(由于移除或调整大小)时,它们会被转换回普通的node节点,容器中节点分布在hash桶中的频率遵循泊松分布,桶的长度超过8的概率非常非常小。所以作者应该是根据概率统计而选择了8作为阀值

    //Java中解释的原因* Because TreeNodes are about twice the size of regular nodes, we* use them only when bins contain enough nodes to warrant use* (see TREEIFY_THRESHOLD). And when they become too small (due to* removal or resizing) they are converted back to plain bins.  In* usages with well-distributed user hashCodes, tree bins are* rarely used.  Ideally, under random hashCodes, the frequency of* nodes in bins follows a Poisson distribution* (http://en.wikipedia.org/wiki/Poisson_distribution) with a* parameter of about 0.5 on average for the default resizing* threshold of 0.75, although with a large variance because of* resizing granularity. Ignoring variance, the expected* occurrences of list size k are (exp(-0.5) * pow(0.5, k) /* factorial(k)). The first values are:** 0:    0.60653066* 1:    0.30326533* 2:    0.07581633* 3:    0.01263606* 4:    0.00157952* 5:    0.00015795* 6:    0.00001316* 7:    0.00000094* 8:    0.00000006* more: less than 1 in ten million

二、哈希表如何解决Hash冲突?

三、为什么HashMap具备下述特点:键-值(key-value)都允许为空、线程不安全、不保证有序、存储位置随时间变化

四、为什么 HashMap 中 String、Integer 这样的包装类适合作为 key 键

五、HashMap 中的 key若 Object类型, 则需实现哪些方法?

参考

jianshu.com/p/8324a34577a0

欢迎在留言区留下你的观点,一起讨论提高。如果今天的文章让你有新的启发,学习能力的提升上有新的认识,欢迎转发分享给更多人。

欢迎各位读者加入订阅号程序员小乐技术群,在后台回复“加群”或者“学习”即可。

猜你还想看

阿里、腾讯、百度、华为、京东最新面试题汇集

面试必问!Java 线程池 8 种拒绝策略!

一文了解 Kafka 分布式!

IntelliJ IDEA 最常用配置详细图解,适合刚刚用的新人!

关注订阅号「程序员小乐」,收看更多精彩内容

嘿,你在看吗

美团面试题:Hashmap的结构,1.7和1.8有哪些区别,史上最深入的分析相关推荐

  1. hashmap value可以为空吗_美团面试题:Hashmap结构,1.7和1.8有哪些区别(最详细解析)...

    作者|依本多情 原文:blog.csdn.net/qq_36520235/article/details/82417949 一.真实面试题之:Hashmap的结构,1.7和1.8有哪些区别 不同点: ...

  2. 美团面试题:Hashmap的结构,1.7和1.8有哪些区别,深入的分析

    (一) 真实面试题之:Hashmap的结构,1.7和1.8有哪些区别 不同点: (1)JDK1.7用的是头插法,而JDK1.8及之后使用的都是尾插法,那么他们为什么要这样做呢?因为JDK1.7是用单链 ...

  3. hashmap中的key是有序的么_美团面试题:Hashmap结构,1.7和1.8有哪些区别(史上最最详细解析)...

    作者|依本多情 原文:blog.csdn.net/qq_36520235/article/details/82417949 一.真实面试题之:Hashmap的结构,1.7和1.8有哪些区别 不同点: ...

  4. 面试中被问到HashMap的结构,1.7和1.8有哪些区别?这篇做深入分析!

    点击上方"Java知音",选择"置顶公众号" 技术文章第一时间送达! 作者:依本多情 blog.csdn.net/qq_36520235/article/det ...

  5. Hashmap 原理、源码、面试题(史上最全)

    文章很长,建议收藏起来慢慢读!疯狂创客圈总目录 语雀版 | 总目录 码云版| 总目录 博客园版 为您奉上珍贵的学习资源 : 免费赠送 :<尼恩Java面试宝典>持续更新+ 史上最全 + 面 ...

  6. Hashmap 面试题 + Hashmap 原理 + Hashmap 源码(史上最全)

    HashMap作为我们日常使用最频繁的容器之一,相信你一定不陌生了.今天我们就从HashMap的底层实现讲起,深度了解下它的设计与优化. 常用的数据结构 我在05讲分享List集合类的时候,讲过Arr ...

  7. 美团面试题:JVM 堆内存溢出后,其他线程是否可继续工作?

    作者:gosaintmrc 来源:http://sina.lt/gqaM 最近网上出现一个美团面试题:"一个线程OOM后,其他线程还能运行吗?" 我看网上出现了很多不靠谱的答案.这 ...

  8. 中数组的合并_【美团面试题】合并两个有序数组

    [美团面试题]合并两个有序数组 题目描述 给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组 划重点 初始化 nums1 和 ...

  9. 美团面试题 | JVM 堆内存溢出后,其他线程是否可继续工作?

    作者:gosaintmrc 来源:http://sina.lt/gqaM 最近网上出现一个美团面试题:"一个线程OOM后,其他线程还能运行吗?" 我看网上出现了很多不靠谱的答案.这 ...

最新文章

  1. 47种常见的浏览器兼容性问题大汇总
  2. apache2.2配置
  3. JAVA基础知识(5)
  4. java随机抽题系统_在用java做一个在线考试系统,随机抽题遇到了问题,我写了一个随机抽题的方法,不知道在asp按钮中怎么用...
  5. java切面获取reqiest,怎么在webflux切面中获取请求头.
  6. pythonanywhere.com的用法
  7. 关于udelay(); mdelay(); ndelay(); msleep();
  8. 监控系统故障定位之事件关联分析的设计
  9. JPA唯一索引更新删除的问题
  10. is not a registered tag library. Must be one of:
  11. 空号筛选接口的应用场景
  12. 如何在VScode中配置python第三方库
  13. 微信小程序 测试号管理(appid和密钥)
  14. 新中大财务软件虚拟化解决方案
  15. hdoj 4747 线段树
  16. 轻松恢复U盘隐藏文件
  17. MATLAB 实现滑轮运转 动态
  18. 熊大微评微内核|华为“鸿蒙”所涉及的微内核究竟是什么?
  19. 工作照制作微信小程序V2.4.21源码
  20. 直流电机 M PWM 调速原理

热门文章

  1. 【合集】Jerry Wang 2018~2021 四年期间的 SAP 技术文章合集
  2. 自动驾驶 11-3: 根据 LIDAR 数据进行位姿估计 Pose Estimation from LIDAR Data
  3. 辐射发射的测试标准和测试方法
  4. 移动App开发 MUI框架 利用软键盘的搜索键实现页面跳转并传值
  5. 安卓手机控制小车(自己做成功了,有全套资料)
  6. 如何编辑PDF文件?简单好用的编辑方法分享
  7. 【Java 工具类】通过出生日期获取年龄
  8. 索引、单列索引、复合索引、主键、唯一索引、聚簇索引、非聚簇索引、唯一聚簇索引 的区别与联系
  9. 应用推广应该遵循的八条黄金法则
  10. php symfony 安装,symfony安装详细教程