HashMap经典面试题汇总
希望本文可以帮助到你
文章目录
前言
大家也可以看这位up的文章,对于HashMap总结的也非常详细!!!
一、HashMap的数据结构,以及存储原理
jdk7 数组+链表
- HashMap map = new HashMap
- 实例化后,底层创建了16的一维数组entry[] table
- …已经执行过多次put操作…
- map.put(key,value)
- 首先调用key1所在类的hashCode()计算key1哈希值,此哈希值经过某种计算后,得到entry存放位置
-
1.如果此位置上的数据为空,此时的key1-value添加成功 ---- 情况1
-
2.如果此位置上不为空,(位置上已经有一个或多个数据-->链表存储) 比较key1和已经存在的一个或多个数据的哈希值
-
如果key1的哈希值与已经存在的数据的哈希值不想同,此时key-value添加成功 情况2
-
如果哈希值与存在数据的某一个相同,调用当前类的equals(),比较key值
-
如果equals()返回false:此时key-value添加成功 ----- 情况3
-
如果equals()返回true:使用value1替换value2
- 补充:关于情况2和情况3 此时key-value是以链表存储
jdk8 数组+链表+红黑树
- JDK8:相较于jdk7在底层实现方面的不同
- 1.new HashMap() 底层没有创建一个长度为16的数组
- 2.jdk8 底层的数组是Node 而非Entry[]
- 3.首次调用put()方法时,底层创建长度为16的数组
- 4.jdk7底层结构只有:数组+链表(单向链表),jdk8中底层结构:数组+链表+红黑树
二、当两个对象的hashCode相同会如何?
hashCode相同的时候
1.会调用equals方法,进行比较key值是否相等,如果key值相等,会将新的value值替代
2.如果key值不相等,会以链表形式存储
三、你知道 hash 的实现吗?为什么要这样实现?
JDK 1.8 中,是通过 hashCode() 的高 16 位异或低 16 位实现的:(h = k.hashCode()) ^ (h >>> 16),主要是从速度,功效和质量来考虑的,减少系统的开销,也不会造成因为高位没有参与下标的计算,从而引起的碰撞。
四、为什么要用异或运算符?
保证了对象的 hashCode 的 32 位值只要有一位发生改变,整个 hash() 返回值就会改变。尽可能的减少碰撞。
五、数组如何扩容的?
创建一个新的数组,其容量为旧数组的两倍,并重新计算旧数组中结点的存储位置。结点在新数组中的位置只有两种,原下标位置或原下标+旧数组的大小。
六、HashMap,LinkedHashMap,TreeMap 有什么区别?
LinkedHashMap 保存了记录的插入顺序,在用 Iterator 遍历时,先取到的记录肯定是先插入的;遍历比 HashMap 慢;
TreeMap 实现 SortMap 接口,能够把它保存的记录根据键排序(默认按键值升序排序,也可以指定排序的比较器)
七、HashMap & TreeMap & LinkedHashMap 使用场景?
一般情况下,使用最多的是 HashMap(重点,主要实现类)。
HashMap:在 Map 中插入、删除和定位元素时;
TreeMap:在需要按自然顺序或自定义顺序遍历键的情况下;
LinkedHashMap:在需要输出的顺序和输入的顺序相同的情况下。
八、HashMap 和 HashTable 有什么区别?
HashMap 是线程不安全的,HashTable 是线程安全的;
由于线程安全,所以 HashTable 的效率比不上 HashMap;
HashMap最多只允许一条记录的键为null,允许多条记录的值为null,而 HashTable不允许;
HashMap 默认初始化数组的大小为16,HashTable 为 11,前者扩容时,扩大两倍,后者扩大两倍+1;
HashMap 需要重新计算 hash 值,而 HashTable 直接使用对象的 hashCode
九、HashMap & ConcurrentHashMap 的区别?
除了加锁,原理上无太大区别。
HashMap的键值对允许有null,但是ConCurrentHashMap 都不允许。
总结
例如:以上就是今天要讲的内容,本文仅仅简单介绍了HashMap的面试题,后续还会有更多面试题新增。