HashMap的面试题

news/2024/5/5 3:45:02/文章来源:https://blog.csdn.net/weixin_52574640/article/details/127872176

目录

1、底层数据结构 1.7和1.8有何不同

2、为什么用红黑树,为何不一上来就树化,树化阈值为何是8,何时会树化,何时会退化为链表

3、索引如何计算?hashCode都有了,为何还要提供hash()方法?数组容量为何是2的n次幂

4、HashMap的put方法流程 1.7和1.8有何不同

5、加载因子为何默认是0.75

6、多线程下操作HashMap(线程不安全的)会有什么问题

7、key是否能为null,作为key的对象有什么要求?

8、String对象的hashCode()如何设计的,为啥每次乘的是31


1、底层数据结构 1.7和1.8有何不同

1.7 数组+链表

1.8 数组+链表+红黑树

2、为什么用红黑树,为何不一上来就树化,树化阈值为何是8,何时会树化,何时会退化为链表

① 红黑树是用来避免DOS攻击,防止链表超长时性能下降,树化应该是偶然情况 1.hash表的查询,时间复杂度是O(1),而红黑树的查找,时间复杂度是O(log2(n)),并且树化占用的空间也普遍比链表大,如非必要,尽量还是使用链表 2.hash值如果只够水机,则在hash表内按照泊松分布,在负载因子是0.75的情况下,长度超过8的链表出现的概率是0.00000006,选择8就是为了让树化的几率足够小

② 树化的两个条件 链表长度大于8 数组容量大于等于64

③ 退化链表的两种情况 1.在扩容的时候,如果拆分树时,树元素个数<=6 则会退化链表(如果是7的话,会频繁进行红黑树和链表的转换,影响性能,所以退了一位,使得不那么容易变回红黑树) 2.remove树结点的时候,如果root,root.left,root.right,root.left.left有一个为null,也会退化为链表

3、索引如何计算?hashCode都有了,为何还要提供hash()方法?数组容量为何是2的n次幂

① 首先计算对象的hashCode(),在调用HashMap的hash()方法进行二次哈希,最后 &(capacity-1)得到索引

// key就是hashCode()的值public V put(K key, V value) {return putVal(hash(key), key, value, false, true);}//hash(key) 是进行二次哈希static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}// n是capacity 数组容量   hahs是二次哈希得到的值p = tab[i = (n - 1) & hash]

② 二次哈希 hash() 是为了综合高位数据,让哈希分布更均匀,防止哈希冲突,使得计算索引的时候,出现相同的概率降低防止出现链表过长的情况

1. HashMap容量较小而hash值比较大的时候,哈希冲突容易变多2. 假设容量为16,那么二进制(0000 1111)进行按位与操作,hash值的高28位不会参与(因为0000 1111前的28位都是0,32位,其中4位符号),所以哈希冲突就会变多3. 进行右移获取的hash值就会让二进制的高位尽可能多地参与按位与操作,从而减少哈希冲突

③ 计算索引的时候 如果是2的n次幂

好处

1.可以使用位运算代替求模运行

(求索引位置是 hash&容量 变成(容量-1)& hash), 因为 &的效率是大于/

2.扩容的时候hash& oldCap == 0 元素就留在原来位置

否则新位置= 旧位置 + oldCap

//扩容的方法中  resize()中 每次都判断
if (oldTab != null) {for (int j = 0; j < oldCap; ++j) {else { // preserve order //维持排序Node<K,V> loHead = null, loTail = null;Node<K,V> hiHead = null, hiTail = null;Node<K,V> next;do {next = e.next;//判断hash& oldCap == 0if ((e.hash & oldCap) == 0) {if (loTail == null)loHead = e;elseloTail.next = e;loTail = e;}//否则else {if (hiTail == null)hiHead = e;elsehiTail.next = e;hiTail = e;}} while ((e = next) != null);//hash& oldCap == 0 loTail 不等于空//保持原来位置if (loTail != null) {loTail.next = null;newTab[j] = loHead;}//否则hiTail 不等于空  新位置 = 原来位置+oldCap(原来的容量)if (hiTail != null) {hiTail.next = null;newTab[j + oldCap] = hiHead;}}}}}

缺点

当例如都是偶数的时候,在如何摸容量 都索引位置都不是奇数,造成哈希表分布性不好

因此 如果追求性能就使用2的n次幂 如果追求哈希表的分布性就使用质数容量

①②③都是配合容量为2的n次幂的优化手段,但是并不能说那种设计更优,应该是设计者综合了各种因素,最终选择了2的n次幂作为容量(HashTable就是不是2的n次幂 扩容长度原来二倍+1)

4、HashMap的put方法流程 1.7和1.8有何不同

  1. HashMap是懒惰创建数组的,首次使用put方法才创建数组(创建对象的时候数组是为空的)

  2. 计算索引(桶下标)

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

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

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

    2. 普通的链表,走链表的添加或者更新逻辑,如果链表长度超过树化的阈值(8) ,数组容量大于等于64就进行树化逻辑

    3. 其中添加和更新逻辑,是看equals是否相等,相等就是更新逻辑,不相等就是添加逻辑

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

  6. 不同

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

    2. 1.7是大于等于阈值且没有空位(就是计算的索引位置有元素)的时候才扩容,而1.8是大于阈值就扩容

    3. 1.8扩容计算Node索引的时候,会优化

5、加载因子为何默认是0.75

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

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

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

6、多线程下操作HashMap(线程不安全的)会有什么问题

①扩容死链(1.7)

多线程的情况会出现这种死链的情况

数组是固定长度,链表太长就需要扩充数组长度进行rehash减少链表长度。如果两个线程同时触发扩容,在移动节点时会导致一个链表中的2个节点相互引用,从而生成环链表

 

②数据错乱(1.7 1.8)

当进行添加的时候

 

线程1添加 a 取得索引为1 线程2添加1 取得索引也为1

例如线程1 进入到630行 执行为null,准备执行631的时候

线程2 进入630行执行也为null 执行631行,结束后 数组索引为1的位置元素为1

然后线程1这个时候已经if 判断完毕了,也执行631行,这个时候就将a放入到数组索引为1的位置

最终出现数据的丢失问题

7、key是否能为null,作为key的对象有什么要求?

  1. HashMap的key可以为null,但是Map的其他实现则不然,会出现空指针异常

  2. 作为key对象,必须实现hashCode和equals ,并且key的内容不能修改(不可变)

    否则修改后hashCode改变了,索引位置改变了,就会出现不同的情况

8、String对象的hashCode()如何设计的,为啥每次乘的是31

public int hashCode() {int var1 = this.hash;if (var1 == 0 && this.value.length > 0) {char[] var2 = this.value;for(int var3 = 0; var3 < this.value.length; ++var3) {var1 = 31 * var1 + var2[var3];}this.hash = var1;}return var1;}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_224084.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ArcGIS计算地形湿度指数

TWI是区域地形对径流流向和蓄积影响的物理指标&#xff0c;有助于识别降雨径流模式、潜在土壤含水量增加区域和积水区域。 计算方法&#xff1a;TWI是通过细尺度地形与上梯度对地表面积的贡献相互作用&#xff0c;根据以下关系得到的(Beven et al.,1979) [1] : TWI ln [CA/…

用专业团队管理软件工具轻松“拿捏”年轻运营团队

本文旨在抛砖引玉&#xff0c;欢迎大家拍砖讨论&#xff0c;通过一款时下流行的专业团队管理软件飞项做案例&#xff0c;一起探讨和交流团队管理专业工具软件和一些对应的方法论。 说到国内这几年流行起来的团队管理工具软件&#xff0c;我们先看看互联网这几年的发展。这几年&…

京东面试题:ElasticSearch 深度分页解决方案

前言 Elasticsearch 是一个实时的分布式搜索与分析引擎&#xff0c;在使用过程中&#xff0c;有一些典型的使用场景&#xff0c;比如分页、遍历等。 在使用关系型数据库中&#xff0c;我们被告知要注意甚至被明确禁止使用深度分页&#xff0c;同理&#xff0c;在 Elasticsearc…

【Python实战】听书就用它了:海量资源随便听,内含几w书源,绝对精品哦~(好消息好消息)

前言 有温度 有深度 有广度 就等你来关注哦~ 所有文章完整的素材源码都在&#x1f447;&#x1f447; 粉丝白嫖源码福利&#xff0c;请移步至CSDN社区或文末公众hao即可免费。 哈喽&#xff01;我是栗子同学&#xff0c;继续更新——今天聊一聊“西马拉雅”。&#xff08;谐音…

特征选择-sklearn

sklearn特征选择:移除低方差特征&#xff1a;单变量特征选择递归特征消除基于模型的SelectFromModel顺序特征选择特征选择作为pipline的一部分sklearn.feature_selection模块中的类可用于样本集的特征选择/降维&#xff0c;以提高估计器的准确性得分或提高其在非常高维的数据集…

BL200OPC UA分布式IO系统接线方式

BL200OPC UA 数据点 Node Id OPC UA 的 Node Id 默认是 NS1&#xff1b;SI/O 数据点的 Modbus 映射地址(如首个 DO 模 块第一路 DO&#xff1a;NS1&#xff1b;S1000)&#xff0c;具体 Modbus 映射地址参考 5.1.4Modbus 寄存器映射&#xff0c; 如果是自定义的 OPC UA 模型 Nod…

(02)Cartographer源码无死角解析-(19) SensorBridge→雷达点云数据预处理(函数重载)

本人讲解关于slam一系列文章汇总链接:史上最全slam从零开始&#xff0c;针对于本栏目讲解(02)Cartographer源码无死角解析-链接如下: (02)Cartographer源码无死角解析- (00)目录_最新无死角讲解&#xff1a;https://blog.csdn.net/weixin_43013761/article/details/127350885 …

3.35 OrCAD中怎么产生Cadence Allegro的第一方网表?OrCAD软件输出Cadence Allegro第一方网表报错时应该怎么处理?

笔者电子信息专业硕士毕业&#xff0c;获得过多次电子设计大赛、大学生智能车、数学建模国奖&#xff0c;现就职于南京某半导体芯片公司&#xff0c;从事硬件研发&#xff0c;电路设计研究。对于学电子的小伙伴&#xff0c;深知入门的不易&#xff0c;特开次博客交流分享经验&a…

cpu与指令集

讨论一下 作为一个java程序员&#xff0c;我们都知道&#xff0c;当我们写完代码&#xff0c;java文件会被编译为class文件&#xff0c;然后交给jvm去执行&#xff0c;那么这个执行过程是啥样的呢&#xff1f;&#xff1f; 一般我们得到的解答都是&#xff0c;class代码会被解…

2、HTML——标题分组、居中、引用标签、水平线标签下划线标签、删除标签、<font>标签、图像标签

目录 一、基本标签 1、标题分组&#xff1a;hgroup 2、居中&#xff1a;center 3、引用标签 3.1 块&#xff08;长&#xff09;引用标签&#xff1a;blockquote 3.2 短引用标签&#xff1a;q 4、水平线标签&#xff1a;hr 5、下划线标签&#xff1a;ins 6、删除标…

【论文笔记之 BLMS】Block Implementation of Adaptive Digital Filters

本文对 GREGORY A. CLARK 于 1981 年在 IEEE Transactions on Circuits and Systems 上发表的论文进行简单地翻译。如有表述不当之处欢迎批评指正。欢迎任何形式的转载&#xff0c;但请务必注明出处。 论文链接&#xff1a;https://ieeexplore.ieee.org/abstract/document/108…

安利几个小技巧教会你ppt如何转pdf

作为一名打工人&#xff0c;特别是办公类&#xff0c;经常是要处理大大小小的文件&#xff0c;有时候甚至要做多种文件转换。并且老板都是多变的&#xff0c;经常突然性就让你把辛苦制作一大半的PPT转成PDF格式的文件再给他。那刚入门的职场小白肯定就会选择&#xff0c;老老实…

我终于读懂了适配器模式。。。

文章目录&#x1f5fe;&#x1f306;什么是适配器模式&#xff1f;&#x1f3ef;类适配器模式&#x1f3f0;对象适配器模式⛺️接口适配器模式&#x1f3ed;适配器模式在SpringMVC 框架应用的源码剖析&#x1f5fc;适配器模式的注意事项和细节&#x1f306;什么是适配器模式&am…

自学软件测试?一般人我还是劝你算了吧...

本人7年测试经验&#xff0c;在学测试之前对电脑的认知也就只限于上个网&#xff0c;玩个办公软件。这里不能跑题&#xff0c;我为啥说&#xff1a;自学软件测试&#xff0c;一般人我还是劝你算了吧&#xff1f;因为我就是那个一般人&#xff01; 软件测试基础真的很简单&…

C# Socket

一 两个人在两个房间里打电话的图 ① 人通过【电话】可以通信&#xff1b; ② 程序通过【Socket】来通信&#xff1b; ③ *套接字 就是 程序间的电话机&#xff1b; ④ 我和孙权打电话 电话 规定好的语言&#xff1b; ⑤ 电脑和电话进行联系 协议&#xff1b; 二 Socket相关…

JVM(二十三)—— 垃圾回收器(三)G1垃圾回收器

G1垃圾回收器:区域化分代式G1概述G1的特点&#xff08;优势&#xff09;G1的缺点G1的参数设置G1的适用场景分区region&#xff1a;化整为零记忆集和写屏障G1回收器垃圾回收过程年轻代GC并发标记过程混合回收G1概述 应用程序所应对的业务越来越庞大&#xff0c;复杂&#xff0c…

【大数据】flink 读取文件数据写入ElasticSearch

前言 es是大数据存储的必备中间件之一&#xff0c;通过flink可以读取来自日志文件&#xff0c;kafka等外部数据源的数据&#xff0c;然后写入到es中&#xff0c;本篇将通过实例演示下完整的操作过程&#xff1b; 一、前置准备 1、提前搭建并开启es服务&#xff08;本文使用doc…

图像分割 - Hough变换直线检测

目录 1. Hough 直线检测 2. HoughLinesP 函数 1. Hough 直线检测 霍夫变换&#xff08;Hough 变换&#xff09;&#xff1a;利用对偶原理&#xff0c;把原空间的问题转换到对偶空间去求解 这里涉及到空间转换&#xff0c;将原来的笛卡尔空间&#xff08;xy空间&#xff09;…

App安全架构之前端安全防护

近年来&#xff0c;随着互联网、物联网、移动设备、5G通讯等技术的齐头发展&#xff0c;人类的生活和工作越来越离不开软件和互联网&#xff0c;正如人类社会文明发展到一定程度以后&#xff0c;会需要法律等社会规范来保护一样&#xff0c;线上环境也是一样道理。 Gartner 对…

Python学习小组课程-课程大纲与Python开发环境安装

一、前言 注意&#xff1a;此为内部小组学习资料&#xff0c;非售卖品&#xff0c;仅供学习参考。 为提升项目落地的逻辑思维能力&#xff0c;以及通过自我创造工具来提升工作效率&#xff0c;特成立Python学习小组。计划每周花一个小时进行在线会议直播学习&#xff0c;面向…