版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
JavaHashMap高频面试题及详细答案(真实面试版)一、基础概念类1.说一说HashMap的底层数据结构?JDK1.7和JDK1.8有什么区别?参考答案:HashMap是基于哈希表实现的键值对存储结构,核心是通过哈希算法定位元素存储位置,保证高效的增删查操作。JDK1.7底层结构:数组+单向链表底层是Entry数组,当发生哈希冲突时,采用头插法将新节点插入对应链表的头部。链表长度无阈值限制,冲突严重时会出现长链表,查询效率大幅降低。JDK1.8底层结构:数组+单向链表+红黑树优化了底层结构,核心改动:1.数组元素改为Node节点,替换了1.7的Entry;2.哈希冲突时,链表长度小于8时继续用链表,链表长度大于等于8且数组容量大于等于64,链表转为红黑树;3.插入节点改为尾插法,避免1.7头插法导致的循环链表问题;4.优化哈希扰动算法,减少哈希冲突概率。2.HashMap的特点是什么?参考答案:1.存储键值对(Key-Value)数据,Key唯一,Value可重复;2.允许Key为null、Value为null,最多只能有一个Key为null;3.线程不安全,多线程环境下会出现数据覆盖、死循环、数据丢失问题;4.无序集合,存取顺序不一致,不保证元素的遍历顺序;5.默认初始容量16,加载因子0.75,达到阈值会自动扩容。3.HashMap和HashTable、ConcurrentHashMap的区别?参考答案:1.HashMapvsHashTable-线程安全:HashTable方法加了synchronized,线程安全;HashMap线程不安全;-空值支持:HashTable不允许Key、Value为null;HashMap允许一个Key为null,多个Value为null;-效率:HashTable锁整张表,并发效率极低;HashMap无锁,单线程效率高;-初始容量:HashTable默认容量11,扩容为2倍+1;HashMap默认16,扩容为2倍。2.HashMapvsConcurrentHashMap-线程安全:ConcurrentHashMap线程安全,是并发场景首选;-锁机制:JDK1.8ConcurrentHashMap采用CAS+synchronized锁单个节点,不锁整张表,并发效率高;-空值:ConcurrentHashMap不允许Key、Value为null,避免并发场景空指针歧义。二、底层原理与哈希机制4.HashMap的哈希算法是怎样的?为什么要做哈希扰动?参考答案:HashMap存储元素时,不会直接使用Key的hashCode值,会经过二次哈希(哈希扰动)计算最终下标。JDK1.8哈希公式:hash=key.hashCode()^(key.hashCode()>>>16)数组下标=(容量-1)&hash扰动目的:1.原始hashCode大多是高位变化、低位不变,直接取模会导致下标集中,冲突多;2.将哈希值的高位特征混合到低位,让哈希值分布更均匀,大幅减少哈希冲突;3.相比1.7的四次扰动,1.8简化为一次扰动,兼顾性能和散列效果。5.为什么数组容量必须是2的幂次?参考答案:核心原因是为了让(容量-1)&hash替代取模运算,提升运算效率。1.二进制中,2的幂次减1的结果是低位全1,比如16-1=15(1111);2.此时与哈希值做与运算,结果等价于hash%容量,位运算速度远高于取模;3.同时能保证哈希下标均匀分布,减少冲突;4.若容量不是2的幂次,(容量-1)二进制会有0位,与运算后部分下标永远无法存储元素,造成空间浪费。6.什么是哈希冲突?HashMap怎么解决哈希冲突?参考答案:不同的Key经过哈希计算后,得到相同的数组下标,就是哈希冲突。HashMap采用链地址法(拉链法)解决冲突:1.多个元素哈希下标相同时,在数组对应位置挂载链表,所有冲突元素挂在同一个链表下;2.JDK1.8优化:链表长度≥8且数组容量≥64时,链表转为红黑树,将查询时间复杂度从O(n)优化为O(logn);3.当红黑树节点数量减少到6时,会退化为链表,避免树结构频繁转换带来的性能损耗。三、扩容与阈值机制7.HashMap的加载因子是什么?默认0.75的原因?参考答案:加载因子(loadFactor)是HashMap扩容的触发系数,扩容阈值=数组容量×加载因子。默认加载因子0.75,是空间和时间效率的最优平衡点:1.加载因子过小(如0.5):扩容频繁,浪费内存空间,但哈希冲突少,查询快;2.加载因子过大(如1.0):填满才扩容,空间利用率高,但哈希冲突极多,链表/树过长,查询效率暴跌;3.0.75是官方经过大量测试的最优值,平衡了空间利用率和查询性能。8.HashMap扩容机制?JDK1.8扩容做了哪些优化?参考答案:扩容触发条件:元素数量超过扩容阈值,或链表转树时数组容量不足64,都会触发扩容。扩容规则:每次扩容容量变为原来的2倍,同时重新计算所有元素的存储下标,迁移元素。JDK1.8扩容核心优化:1.7扩容时需要重新哈希所有元素,逐个计算下标,效率低;1.8无需完整重哈希,利用2倍扩容特性:元素新下标只有两种可能,原下标或原下标+旧容量。遍历链表节点时,通过哈希值高位判断,直接拆分链表为两组,分别迁移,大幅提升扩容效率。9.为什么链表转红黑树阈值是8,退化为链表是6?参考答案:1.阈值8的原因:根据哈希分布统计,正常哈希情况下,链表长度达到8的概率极低,大概率是哈希冲突严重、恶意哈希或哈希算法失效导致,此时转树可以大幅提升查询效率;同时避免少量节点频繁建树,减少建树开销。2.退化为6的原因:预留2个节点的缓冲区间,防止链表和红黑树频繁互相转换。如果转树和退化阈值都是8,节点数量在8左右波动时,会反复树化、退链,造成严重性能损耗。3.节点数7时保持树结构,6时退化,有效规避频繁转换的性能问题。四、源码与核心方法细节10.HashMap的put方法执行流程?参考答案:完整执行流程如下:1.先判断数组是否为空或长度为0,若是,执行首次初始化扩容;2.计算Key的哈希值,通过位运算得到数组下标;3.判断对应下标位置是否为空,为空则直接新建节点存入,结束流程;4.若位置不为空,说明存在元素,判断头节点Key是否和当前Key一致,一致则覆盖Value;5.若头节点是树节点,执行红黑树的插入逻辑;6.若为链表结构,遍历链表查找相同Key,找到则覆盖Value;遍历到链表末尾未找到,则尾插新节点;7.插入新节点后,判断链表长度是否≥8,满足则触发树化(同时校验数组容量≥64);8.最后判断元素总数量是否超过扩容阈值,超过则执行扩容。11.HashMap中Key为什么必须重写equals和hashCode方法?只重写一个会怎样?参考答案:HashMap去重逻辑依赖先比对hashCode,再比对equals的双重校验机制:1.存储时先通过hashCode定位下标,下标一致再通过equals判断是否为同一个Key;2.只重写hashCode,不重写equals:两个内容相同的对象,hashCode一致,但默认equals比较地址,会被判定为不同Key,导致存储重复数据,无法去重;3.只重写equals,不重写hashCode:默认hashCode返回对象地址,相同内容对象哈希值不同,会存储在不同下标,导致明明是同一个Key,却无法覆盖,出现重复键值对;4.结论:自定义对象作为HashMap的Key,必须同时重写hashCode和equals。五、并发问题与坑点12.为什么HashMap线程不安全?会出现哪些问题?参考答案:HashMap所有方法均无并发锁控制,多线程操作时存在严重线程安全问题:1.数据覆盖:多个线程同时put元素,定位到同一个下标,后插入的节点会覆盖先插入的节点,导致数据丢失;2.JDK1.7扩容死循环:头插法扩容时,多线程并发迁移节点,会导致链表形成环形结构,后续get元素时出现死循环,CPU占用100%;3.元素丢失、size统计错误:多线程同时修改size变量,未加锁会导致计数不准,实际元素数量和size不一致。注:JDK1.8改为尾插法,解决了扩容死循环问题,但依然存在数据覆盖、size不准问题,依旧线程不安全。13.HashMap为什么不允许Value为null?(误点纠正:ConcurrentHashMap不允许,HashMap允许)参考答案:HashMap是允许Value为null,且允许多个Value为null;也允许一个Key为null。真正不允许空值的是ConcurrentHashMap,原因:并发场景下,无法区分get(key)返回null是Key不存在,还是Key存在但Value为null,会产生业务歧义,引发并发逻辑错误。而HashMap是单线程使用,开发者可通过containsKey单独判断Key是否存在,无歧义。14.遍历HashMap时删除元素会怎样?为什么?参考答案:1.普通for循环/增强for循环遍历删除:直接抛出ConcurrentModificationException并发修改异常;2.迭代器Iterator遍历删除:可以正常删除,不会报错。原理:HashMap内部有modCount变量,记录结构修改次数(增、删、扩容都会累加)。迭代器遍历过程中,会实时比对modCount和迭代器初始化的expectedModCount,不一致就抛异常。普通删除方法会修改modCount,但不更新expectedModCount;而迭代器自带的remove方法,会同步更新两个变量,所以不会触发异常。六、高频进阶面试题15.HashMap的get方法为什么高效?时间复杂度是多少?参考答案:1.最优情况:无哈希冲突,直接通过哈希定位数组下标,时间复杂度O(1);2.冲突为链表:遍历链表查询,复杂度O(n);3.冲突转为红黑树:树查询二分遍历,复杂度O(logn);日常使用中,哈希算法散列均匀,极少出现长链表,所以整体查询效率接近O(1)。16.初始化HashMap时,指定初始容量有什么意义?如何正确设置初始容量?参考答案:1.不指定初始容量:默认16,数据量较大时会频繁触发扩容,扩容需要重新哈希、迁移元素,损耗性能;2.指定合理初始容量:可减少扩容次数,提升程序性能。正确设置公式:预估元素数量÷0.75+1,再向上取2的幂次。比如预估存储100个元素:100/
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 内蒙古鄂尔多斯准格尔旗第四中学2027届数学九上期末质量跟踪监视试题含解析
- 2026年四川省数控编程与仿真综合练习题及答案
- 2026年外研版初中英语下册第9单元语法练习题及答案
- 2026中国嗜酸性粒细胞增多症靶向药物研发竞争态势报告
- 2026秋小学体育北京版(新教材)一年级全一册每课教学设计(附教学目录)
- 2026中国智能制造行业市场发展趋势与商业价值分析
- 脑梗高血压护理查房
- 2026中国高端装备制造产业竞争力与国际市场拓展报告
- 2026云计算服务产业链深度解析与商业模式创新报告
- 上海体育大学2024年运动康复计划(运动康复康复心理学临床)试题及答案
- 中国邮政储蓄银行2027届校园招聘笔试备考试题及答案解析
- 2025年广州市海珠区事业单位人员招聘考试试题及答案详解
- 2.7.2 勾股定理的逆定理 课件 -2026-2027学年浙教版数学八年级上册
- 2026年融媒体新闻采编技术应用及理论知识考试题库(附含答案)
- 2026国企招聘考试公共基础知识考试题(含答案)
- 髋、膝关节置换术后护理及功能康复
- 人工挖孔灌注桩安全技术交底培训
- 2025年银行考试-银行间本币市场交易员资格笔试考试历年典型考题及考点
- 内支撑设计计算书(Excel自动计算版)
- GB/T 29717-2026滚动轴承风力发电机组偏航、变桨轴承
- 新版2025-2026部编人教版小学语文1一年级上册(全册)教案设计合集
评论
0/150
提交评论