HashMap常见面试题

1.有没有了解过HashMap底层是怎么实现的?

1、整体类继承结构

2、主要特点

(1) 数据以键值(key-value)对方式存储的一个集合容器;

(2) Key不重复;

(3) 可以使用null的键和null的值;

(4) 不保证key-value映射的顺序;

(5) 非线程安全实现的;

3、数据结构

在JDK1.7中,由 数组+链表 构成;

在JDK1.8中,由 数组+链表+红黑树 构成;

HashMap默认数组16长度,会进行哈希运算放入不同的位置,当有两个值需要放入相同位置是,会在当前位置挂一个链表存入,数据扩容到64并且链表长度达到8的时候在JDK1.8会变成红黑树存储,性能更好

4、HashMap性能参数

(1)初始容量capacity:创建数组的长度默认是16,如果太少,很容易触发扩容,如果太多,遍历数组会比较慢;

(2)负载因子loadFactor:一个衡量的尺度,数组长度达到多少的时候触发数组自动扩容,默认为0.75;

(3)阈值threshold:阈值=容量*负载因子,默认16*0.75=12,当元素数量超过阈值时触发扩容;

2.多线程条件下HashMap有什么问题吗?

1、多线程条件下会导致死循环问题,导致CPU 100%;

2、多线程put可能导致元素丢失;

3、put和get并发时,可能导致get为null;

3.HashMap链表节点过深时为什么选择使用红黑树?

二叉树

1、二叉查找树(二叉搜索树

特点:

1、每个节点最多只能有两个子节点;

2、左子树的键值小于根的键值(hash值),右子树的键值大于等于根的键值;

3、对二叉查找树的节点进行查找时,深度为1的节点查找次数为1,深度为2节点查找次数为2,深度为3的节点查找次数为3,深度为n的节点查找次数为n,因此查找时间复杂度依赖于节点深度,如果节点很深,则查找效率降低;

4、极端情况下,如果键值是顺序增大的,则二叉查找树"退化"为像链表的结构;

2、强平衡二叉查找树

为了提高二叉查找树的的查找效率,引入了一种新的数据结构:平衡二叉查找树(也叫AVL树:1962 年G. M. Adelson-Velsky 和 E. M. Landis两个人提出来的); 平衡二叉查找树(AVL树)在满足二叉查找树的条件下,还需满足任何节点的两个子树的高度最大差为1,所以它呈现出是一种左右平衡的状态;(height <=1)所以左图是右图不是

3、弱平衡二叉查找树(红黑树)

(1)每个节点要么是红的要么是黑的;

(2)根节点和叶节点(叶节点即指树尾端NIL节点)都是黑的;

(3)如果一个结点是红的,那么它的两个子节点都是黑的(不可能连续两个红色节点,但是可以连续两个黑色节点);

(4)任意节点到叶节点的链路中都包含相同数目的黑节点;

总结:

①由于二叉查找树,查找速度取决于深度在极端情况下会变成和链表一样的结构,降低速度

②平衡二叉树需要满足任意两节点高度差<=1,所以在进行增删操作会出现自旋转,呈现平衡状态

红黑树也是一种平衡二叉树,但是没有高度差<=1这个限制;相同的节点个数的情况下,红黑数的旋转次数比平衡二叉树(AVL)树要少,所以对于插入、删除操作较多的情况下,使用红黑树会更好;

④在相同节点个数的情况下,AVL树的高度<=红黑树,如果应用只是对查找要求较高,那么AVL树要优于红黑树;

所以HashMap选择红黑树

4.什么是hash碰撞,发生hash碰撞怎么办?

定义:对于不同的关键字,可能得到同一个哈希地址,即key1≠key2,而 f(key1)=f(key2),对于这种现象我们称之为哈希碰撞,也叫哈希冲突;

一般哈希冲突只能尽量地减少,无法完全避免,因为关键字在理论上可以有无限多个,而用来存储这些关键字的数组容量是有限的,所以就必然会导致了哈希冲突,只能通过选择合适的哈希函数来降低哈希冲突发生的概率;

Hash冲突的解决办法:

1、开放定址法;

开放定址法是指当发生哈希冲突的时候,按照某种方法继续探测哈希表中的其他存储位置,一直找到空位置为止; 比如在插入50这个元素时,发现要插入的位置已经存在元素了,我们用开放定址法来解决这个哈希冲突; 过程分析: 第一次计算50要插入的是2号位置,而2号位置已经存在元素18了,那么就将2加1得到3,然后再查看3号位置是否有元素,发现3号位置是空的,那么就可以把50这个元素放在3号位置了;

2、再哈希法; 当发生哈希冲突的时候就再次哈希,直至不发生冲突为止;(对余数再哈希)

3、链地址法(拉链法)--> HashMap采用是该办法 链地址法是指碰到哈希冲突的时候,将冲突的元素以链表的形式进行存储,也就是只要哈希地址相同的元素,都插入到同一个链表中,元素的插入方式可以是头插法,也可以是尾插法;

链地址法是比较常用的一种解决哈希冲突的方式,HashMap采用的是这种链地址法(拉链法),当发生冲突时,将新结点添加在链表后面; 虽然这是一种不错的处理方式,但是也存在一些明显的弊端,在极端情况下,他的查询时间复杂度还是会达到O(n)级别,此时哈希表已经退化成了一个普通的链表,在这种结构下去查找一个元素,时间复杂度是O(n),因此,在链表达到一定长度的时候,把链表转化成一棵树可以提高查找效率,HashMap的源码中就是这么实现的,当数组的长度大于64,且数组某个位置上的链表的长度大于8时,就会把数组某个位置上的链表转换成一棵红黑树(O(logN));

5.请介绍一下ConcurrentHashMap底层是怎么实现的?

ConcurrentHashMap是线程安全的,他的结构是Segment\[\]和HashEntry\[\]两个数组后面再加链表,加锁是通过ReentranLock锁在Segment上加锁默认是长度16相当于可以加16把锁,然后值通过哈希运算存入HashEntry数组 ,这个数组也可以扩容,遇到相同的存入位置会在后面挂一个链表

JDK1.7 数据结构:

Segment\[\]数组 + HashEntry\[\]数组 + 链表;

线程安全: Segment继承ReentrantLock,采用分段锁(默认16把锁),每一把锁只锁一个Segment;

在JDK1.8中ConcurrentHashMap跟HashMap结构差不多,但是保证了线程安全,将值进行哈希运算,相同位置会增加链表,等数组扩展到64以及链表长度为8时,链表变成红黑树结构。

JDK1.8 数据结构:

Node\[\]数组+链表+红黑树

线程安全: 初始化Node数组采用CAS+volatile; 放数据时采用synchronized;

相关推荐
J2虾虾11 小时前
Spring AI Alibaba文档
java·人工智能·spring
YikNjy11 小时前
break和continue
java·开发语言·算法
SomeOtherTime11 小时前
Geojson相关(AI回答)
java·前端·python
日月云棠11 小时前
10 Integer —— 最常用的整数包装类深度解析
java·后端
秋911 小时前
java项目中cpu飙升排查及解决方法
java·开发语言
野生技术架构师11 小时前
牛客网2026最新大厂Java高频面试题精选(附标准答案)
java·开发语言
PH = 711 小时前
JAVA的SPI机制
java·开发语言
一 乐11 小时前
高校实习信息发布网站|基于Spring Boot的高校实习信息发布网站的设计与实现(源码+数据库+文档)
java·数据库·spring boot·后端·论文·毕设·高校实习信息发布网站
weelinking11 小时前
【产品】11_实现后端接口——数据在背后如何流动
java·人工智能·python·sql·oracle·json·ai编程
摇滚侠11 小时前
东方通替换tomcat,实战经验
java