HashMap:
1、如何解决Hash冲突
Hash冲突出现原因是多个Key进过Hash算法所得到的结果相同,此时需要添加一个链表来解决。
2、JDK1.7和JDK1.8主要区别
JDK1.7采用的是数组加链表 JDK1.8采用的是数组加链表加红黑树
当数组的长度大于64,并且链表的长度大于等于8时,链表会转换为红黑树。
为什么是8?
通过查看源码里面有个泊松分布显示链表长度达到8的概率是非常低的大概是千万分之一
当链表的长度小于6时,会由红黑树转换为链表。
为什么是6?
如果是8的话当出现Hash冲突时会在链表和红黑树之间来回转换影响效率,7作为分水岭,所以选择6.
3、扩容时机
当数组的长度达到数组长度*加载因子时,数组会进行扩容。
当链表的长度达到8但是数组的长度小于64时,数组会进行扩容。
为什么加载因子是0.75?
因为如果是1的话虽然充分利用了空间,但是容易发生Hash冲突,那么新添加的元素会存放在链表下,导致查询效率低
0.5的话则会出现浪费空间的问题,所以0.75是比较合适的。
为什么是2的幂次方扩容?
因为hashmap底层采用的是二进制位的运算方式,2的幂次方减一之后,后几位是全为1的,再去和Key的HashCode进行与运算,这种情况下index的结果就等于hashcode的后几位的值,只要HashCode本身是分布均匀的,Hash算法的结果就是均匀的,这样就减少了Hash冲突。
4、HashMap高并发情况下为什么会出现死循环?
当多个线程同时触发扩容时,可能操作的是同一个桶下面的的数据,这时如果一个线程执行完了,而另外一个线程在执行过程中出现了一些问题然后恢复了再次执行下面的操作时,由于采用的是头插法,需要遍历将桶下面的元素重新分配到新的位置,假设没有扩容前的顺序是C->B->A,第一个线程执行完扩容操作后,和之前的顺序相反A->B->C,另外一个线程在执行过程按照之前的顺序从C开始,C的next指向B从而导致节点的死循环。
https://blog.csdn.net/sufu1065/article/details/122891566
使用ConcurrentHashMap来解决循环依赖。
JUC 包下的一个集合类,它由多个Segment组成(本身相当于一个Hashmap对象),Put操作时,锁的是某个Segment,其他线程对其他Segment的读写操作均不影响。
5、Hashtable和HashMap的区别
两者父类不同:Hashmap继承自AbstractMap类 hashtable继承自Dictionary类
对外提供的接口不同:Hashtable多提供了elments()和contains()方法
对null的支持不同:HashMap允许Key、value都为null。
安全性不同:Hashtable安全但是效率不高使用concurrentHashmap
初始容量大小和每次扩容大小不同:Hashmap每次扩容是2的幂次方初始容量为16 ;Hashtable每次扩容是乘二加一初始容量为:11
6、hashmap的getkey和getentry哪个效率高
entry.getvalue可以直接拿到value,hashmap.get(key)是先得到Entry对象,再通过entry.getvalue去拿,getEntry效率更高
7、HashMap的put方法
①判断数组的容量是否为空,为空初始化数组的大小16
②key为null,将key对应的value值放到index为0的位置,如key存在则还回旧的值将新的值添加进去
③key不为null,调用方法计算Hash值,根据HashCode和数组的长度找到对应的下标,遍历当前下标位置的链表的,比较HashCode值和key是否相同,相同就替换为当前的值,不同则添加到当前链表下面。
④modCount++
⑤将添加到链表中,先判断是否需要扩容。
HashMap高频面试题
最新推荐文章于 2024-11-01 14:48:20 发布