一文搞懂所有HashMap面试题

2020-11-26  本文已影响0人  dybaby

刚刚经历过秋招,看了大量的面经,HashMap是面试的高频问题,这里将HashMap常见面试题总结了一下,并根据被问到的频率大致做了一个标注。问题后面的星数量越多表示,在面试中出现的频率越高,搞懂下面所有的问题,就再也不用担心面试官问你HashMap了。

微信搜索公众号路人zhang,回复面试手册,领取本文档PDF版及更多面试资料。

推荐阅读:一文搞懂所有Java基础知识面试题

Map集合

HashMap在JDK1.7和JDK1.8中有哪些不同?HashMap的底层实现 ***

在这里插入图片描述 在这里插入图片描述

HashMap在JDK1.7和JDK1.8中有哪些不同点:

JDK1.7 JDK1.8 JDK1.8的优势
底层结构 数组+链表 数组+链表/红黑树(链表大于8) 避免单条链表过长而影响查询效率,提高查询效率
hash值计算方式 9次扰动 = 4次位运算 + 5次异或运算 2次扰动 = 1次位运算 + 1次异或运算 可以均匀地把之前的冲突的节点分散到新的桶(具体细节见下面扩容部分)
插入数据方式 头插法(先讲原位置的数据移到后1位,再插入数据到该位置) 尾插法(直接插入到链表尾部/红黑树) 解决多线程造成死循环地问题
扩容后存储位置的计算方式 重新进行hash计算 原位置或原位置+旧容量 省去了重新计算hash值的时间

HashMap 的长度为什么是2的幂次方 ***

因为HashMap是通过key的hash值来确定存储的位置,但Hash值的范围是-2147483648到2147483647,不可能建立一个这么大的数组来覆盖所有hash值。所以在计算完hash值后会对数组的长度进行取余操作,如果数组的长度是2的幂次方,(length - 1)&hash等同于hash%length,可以用(length - 1)&hash这种位运算来代替%取余的操作进而提高性能。

HashMap的put方法的具体流程? **

HashMap的主要流程可以看下面这个流程图,逻辑非常清晰。

在这里插入图片描述

HashMap的扩容操作是怎么实现的? ***

HashMap默认加载因子为什么选择0.75?

这个主要是考虑空间利用率和查询成本的一个折中。如果加载因子过高,空间利用率提高,但是会使得哈希冲突的概率增加;如果加载因子过低,会频繁扩容,哈希冲突概率降低,但是会使得空间利用率变低。具体为什么是0.75,不是0.74或0.76,这是一个基于数学分析(泊松分布)和行业规定一起得到的一个结论。

为什么要将链表中转红黑树的阈值设为8?为什么不一开始直接使用红黑树?

可能有很多人会问,既然红黑树性能这么好,为什么不一开始直接使用红黑树,而是先用链表,链表长度大于8时,才转换为红红黑树。

HashMap是怎么解决哈希冲突的? ***

哈希冲突:hashMap在存储元素时会先计算key的hash值来确定存储位置,因为key的hash值计算最后有个对数组长度取余的操作,所以即使不同的key也可能计算出相同的hash值,这样就引起了hash冲突。hashMap的底层结构中的链表/红黑树就是用来解决这个问题的。

HashMap中的哈希冲突解决方式可以主要从三方面考虑(以JDK1.8为背景)

HashMap为什么不直接使用hashCode()处理后的哈希值直接作为table的下标? ***

hashCode()处理后的哈希值范围太大,不可能在内存建立这么大的数组。

能否使用任何类作为 Map 的 key? ***

可以,但要注意以下两点:

为什么HashMap中String、Integer这样的包装类适合作为Key? ***

如果使用Object作为HashMap的Key,应该怎么办呢? **

HashMap 多线程导致死循环问题 ***

由于JDK1.7的hashMap遇到hash冲突采用的是头插法,在多线程情况下会存在死循环问题,但JDK1.8已经改成了尾插法,不存在这个问题了。但需要注意的是JDK1.8中的HashMap仍然是不安全的,在多线程情况下使用仍然会出现线程安全问题。基本上面试时说到这里既可以了,具体流程用口述是很难说清的,感兴趣的可以看这篇文章。HASHMAP的死循环

ConcurrentHashMap 底层具体实现知道吗? **

在这里插入图片描述 在这里插入图片描述

总结一下:

HashTable的底层实现知道吗? **

HashTable的底层数据结构是数组+链表,链表主要是为了解决哈希冲突,并且整个数组都是synchronized修饰的,所以HashTable是线程安全的,但锁的粒度太大,锁的竞争非常激烈,效率很低。

在这里插入图片描述

HashMap、ConcurrentHashMap及Hashtable 的区别 ***

HashMap(JDK1.8) ConcurrentHashMap(JDK1.8) Hashtable
底层实现 数组+链表/红黑树 数组+链表/红黑树 数组+链表
线程安全 不安全 安全(Synchronized修饰Node节点) 安全(Synchronized修饰整个表)
效率 较高
扩容 初始16,每次扩容成2n 初始16,每次扩容成2n 初始11,每次扩容成2n+1
是否支持Null key和Null Value 可以有一个Null key,Null Value多个 不支持 不支持

Map的常用方法 **

这些常用方法是需要背下来的,虽然面试用不上,但是笔试或者面试写算法题时会经常用到。

方法
void clear() 清除集合内的元素
boolean containsKey(Object key) 查询Map中是否包含指定key,如果包含则返回true
Set entrySet() 返回Map中所包含的键值对所组成的Set集合,每个集合元素都是Map.Entry的对象
Object get(Object key) 返回key指定的value,若Map中不包含key返回null
boolean isEmpty() 查询Map是否为空,若为空返回true
Set keySet() 返回Map中所有key所组成的集合
Object put(Object key,Object value) 添加一个键值对,如果已有一个相同的key,则新的键值对会覆盖旧的键值对,返回值为覆盖前的value值,否则为null
void putAll(Map m) 将制定Map中的键值对复制到Map中
Object remove(Object key) 删除指定key所对应的键值对,返回所关联的value,如果key不存在返回null
int size() 返回Map里面的键值对的个数
Collection values() 返回Map里所有values所组成的Collection
boolean containsValue ( Object value) 判断映像中是否存在值 value
上一篇下一篇

猜你喜欢

热点阅读