经典面试题收集二
-
- 第四章(Map)
-
- [1. 用过哪些Map实现](#1. 用过哪些Map实现)
- 2.说一下HashMap和HashTable的区别
- [3. 介绍一下hashCode()和equals()的使用场景](#3. 介绍一下hashCode()和equals()的使用场景)
- [4. HashMap和TreeMap应该怎么选择,使用场景?](#4. HashMap和TreeMap应该怎么选择,使用场景?)
- [5. Set和Map的关系](#5. Set和Map的关系)
- [6. 常见的Map排序规则是怎样的?](#6. 常见的Map排序规则是怎样的?)
- [7. 如果需要线程安全且效率高的Map,应该怎么做?](#7. 如果需要线程安全且效率高的Map,应该怎么做?)
- [8. 看过HashMap源码吗,介绍一下你了解的HashMap](#8. 看过HashMap源码吗,介绍一下你了解的HashMap)
- [9. 能否解释下什么是Hash碰撞?常见的解决办法有哪些,hashmap采样哪种方法?](#9. 能否解释下什么是Hash碰撞?常见的解决办法有哪些,hashmap采样哪种方法?)
- [10. 为什么要使用数组+链表+红黑树这几种数据结构?](#10. 为什么要使用数组+链表+红黑树这几种数据结构?)
- [11. 为什么选择红黑树而不用其它树,为什么一开始不用红黑树,而是到8长度后转成红黑树](#11. 为什么选择红黑树而不用其它树,为什么一开始不用红黑树,而是到8长度后转成红黑树)
- [12. 说下hashmap的put和get的核心逻辑](#12. 说下hashmap的put和get的核心逻辑)
- [13. 了解ConcurrentHashMap吗?为什么性能比hashtable高,说下原理](#13. 了解ConcurrentHashMap吗?为什么性能比hashtable高,说下原理)
- [14. jdk1.7和1.8里面ConcurrentHashMap实现的区别有了解吗](#14. jdk1.7和1.8里面ConcurrentHashMap实现的区别有了解吗)
第四章(Map)
1. 用过哪些Map实现
matlab
复制代码
HashMap、LinkedHashMap、ConcurrentHashMap
2.说一下HashMap和HashTable的区别
matlab
复制代码
//HashMap:底层基于数组+链表,非线程安全,默认容量是16,允许有空的键和值
//Hashtable:基于哈希表实现,线程安全(加了synchronized),默认容量是11,不允许有null的键和值
3. 介绍一下hashCode()和equals()的使用场景
matlab
复制代码
//hashcode:顶级类Object⾥⾯的⽅法,所有的类都是继承Object,返回是⼀个int类型的数,根据⼀定的hash规则(存储地址,字段,⻓度等),映射成⼀个数组,即散列值
//equals:顶级类Object⾥⾯的⽅法,所有的类都是继承Object,返回是⼀个boolean类型,根据⾃定义的匹配规则,⽤于匹配两个对象是否⼀样
//⼀般逻辑如下:
//判断地址是否⼀样,⾮空判断和Class类型判断
//强转
//对象⾥⾯的字段⼀⼀匹配
//使⽤场景:对象⽐较、或者集合容器⾥⾯查重、⽐较、排序
4. HashMap和TreeMap应该怎么选择,使用场景?
matlab
复制代码
//HashMap:散列桶(数组+链表),可以实现快速的存储和检索,但是里面的元素是无序的,适合在map中插入、删除和定位
//TreeMap:存储结构是一个平衡二叉树-红黑树,可以自定义排序规则,要实现Comparator接口,能便捷的实现内部元素的各种排序,但是性能一般比HashMap差,适用于自然排序或自定义排序规则
5. Set和Map的关系
matlab
复制代码
//核⼼就是不保存重复的元素,存储⼀组唯⼀的对象
//set的每⼀种实现都是对应Map⾥⾯的⼀种封装
//HashSet对应的就是HashMap,treeSet对应的就是treeMap
6. 常见的Map排序规则是怎样的?
matlab
复制代码
//按照添加顺序使⽤LinkedHashMap
//按照⾃然排序使⽤TreeMap
//⾃定义排序TreeMap(Comparetor c)
7. 如果需要线程安全且效率高的Map,应该怎么做?
matlab
复制代码
//多线程环境下可以使用concurrent包下的ConcurrentHashMap,或者使用Collections.synchronizedMap()
8. 看过HashMap源码吗,介绍一下你了解的HashMap
matlab
复制代码
//HashMap底层(数组+链表+红⿊树 jdk8才有红⿊树)
//数组中每⼀项是⼀个链表,即数组和链表的结合体
//Node[] table 是数组,数组的元素是Entry(Node继承Entry),Entry元素是⼀个 key-value的键值对,它持有⼀个指向下个Entry的引⽤,table数组的每个Entry元素同时也作为当前Entry链表的⾸节点,也指向了该链表的下个Entry元素。在JDK1.8中,链表的⻓度⼤于8,链表会转换成红⿊树
9. 能否解释下什么是Hash碰撞?常见的解决办法有哪些,hashmap采样哪种方法?
matlab
复制代码
//hash碰撞的意思是不同key计算得到的Hash值相同,需要放到同个bucket中
//常⻅的解决办法:链表法、开发地址法、再哈希法等
//HashMap采⽤的是链表法
10. 为什么要使用数组+链表+红黑树这几种数据结构?
matlab
复制代码
//数组Node[] table,根据对象的key的hash值决定在数组⾥⾯是哪个节点
//链表的作⽤是解决hash冲突
//红⿊树,JDK8使⽤红⿊树来替代超过8个节点的链表,主要是查询性能的提升,从原来的O(n)到 O(logn), 通过hash碰撞,让HashMap不断产⽣碰撞,那么相同的key的位置的链表就会不断增⻓,当对这个Hashmap的相应位置进⾏查询的时候,就会循环遍历这个超级⼤的链表,性能就会下降,所以改⽤红⿊树
11. 为什么选择红黑树而不用其它树,为什么一开始不用红黑树,而是到8长度后转成红黑树
matlab
复制代码
//⼆叉查找树在特殊情况下也会变成⼀条线性结构,和原先的链表存在⼀样的深度遍历问题,查找性能就会慢,使⽤红⿊树主要是提升查找数据的速度
//红⿊树是平衡⼆叉树的⼀种,插⼊新数据后会通过左旋,右旋、变⾊等操作来保持平衡,解决单链表查询深度的问题
//数据量少的时候操作数据,遍历线性表⽐红⿊树所消耗的资源少,且前期数据少,平衡⼆叉树保持平衡是需要消耗资源的,所以前期采⽤线性表,等到⼀定数之后变换到红⿊树
12. 说下hashmap的put和get的核心逻辑
matlab
复制代码
put方法:
当你调用put(key, value)时,HashMap首先会根据key的hashCode计算出一个哈希值。
然后,通过哈希值和HashMap的容量找到对应的桶(数组位置)。
如果该桶为空,直接将键值对放入桶中;如果不为空,可能发生哈希冲突(不同的key有相同的哈希值),这时通常会使用链表或红黑树等数据结构来存储冲突的键值对。
如果链表长度过长(达到8个),会将链表转换为红黑树,以提高查询效率。
get方法:
当你调用get(key)时,HashMap会根据key的hashCode计算出哈希值,并找到对应的桶。
如果桶为空,说明没有找到对应的键值对,返回null。
如果桶不为空,可能存在哈希冲突,HashMap会遍历桶内的链表或红黑树,找到匹配的key。
返回找到的value。
总体来说,HashMap的put和get操作都依赖于哈希值的计算和桶的管理。哈希表的设计使得在理想情况下,put和get的时间复杂度是常数级别的,即O(1)。不过,在发生哈希冲突时,需要通过链表或红黑树来处理,这可能会引入一些额外的复杂性。
13. 了解ConcurrentHashMap吗?为什么性能比hashtable高,说下原理
matlab
复制代码
ConcurrentHashMap线程安全的Map, hashtable类基本上所有的⽅法都是采⽤synchronized 进⾏线程安全控制 ⾼并发情况下效率就降低
ConcurrentHashMap是采⽤了分段锁的思想提⾼性能,锁粒度更细化
14. jdk1.7和1.8里面ConcurrentHashMap实现的区别有了解吗
matlab
复制代码
JDK8之前,ConcurrentHashMap使⽤锁分段技术,将数据分成⼀段段存储,每个数据段配置⼀把锁,即segment类,这个类继承ReentrantLock来保证线程安全
技术点:Segment+HashEntry
JKD8的版本取消Segment这个分段锁数据结构,底层也是使⽤Node数组+链表+红⿊树,从⽽实现对每⼀段数据就进⾏加锁,也减少了并发冲突的概率,CAS(读)+Synchronized(写)
技术点:Node+Cas+Synchronized