本文的真题来自某网友整理,针对他的面经整理的答案,但大家可以在我的主页里均可找到,本人的《Java面试必知必会》系列在继续更新中,目前已经更新到SpringBoot,后续还会更新计算机基础相关的内容。
想看更多大厂的面试问题,请关注我的主页,《Java面试必知必会》系列更新完后,后面会更新国内各个大厂的面试问题,敬请期待!记得点赞、收藏和关注哦,你们的支持是我创作的最大动力哦!
1.HashMap的底层原理?扩容?线程安全的吗?
回答:在jdk1.7之前HashMap是基于数组和链表实现的,而且采用头插法。
而jdk1.8 之后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为 8)(将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树)时,将链表转化为红黑树,以减少搜索时间。采用尾插法。
HashMap默认的初始化大小为 16。当HashMap中的元素个数之和大于负载因子*当前容量的时候就要进行扩充,容量变为原来的 2 倍。(这里注意不是数组中的个数,而且数组中和链/树中的所有元素个数之和!)
注意:我们还可以在预知存储数据量的情况下,提前设置初始容量(初始容量 = 预知数据量 / 加载因子)。这样做的好处是可以减少 resize() 操作,提高 HashMap 的效率
美团面试的时候问到这个问题,还给出具体的值,让我算出初始值设置为多少合适?
HashMap是线程不安全的,其主要体现:
1.在jdk1.7中,在多线程环境下,扩容时会造成环形链或数据丢失。
2.在jdk1.8中,在多线程环境下,会发生数据覆盖的情况。
追问:HashMap扩容的时候为什么是2的n次幂?
回答:数组下标的计算方法是(n - 1) & hash,取余(%)操作中如果除数是2的幂次则等价于与其除数减一的与(&)操作(也就是说 hash%length==hash&(length-1)的前提是 length 是2的 n 次方;)。” 并且 采用二进制位操作 &,相对于%能够提高运算效率,这就解释了 HashMap 的长度为什么是2的幂次方。
追问:HashMap的put方法说一下。
回答:通过阅读源码,可以从jdk1.7和1.8两个方面来回答
1.根据key通过哈希算法与与运算得出数组下标
2.如果数组下标元素为空,则将key和value封装为Entry对象(JDK1.7是Entry对象,JDK1.8是Node对象)并放入该位置。
3.如果数组下标位置元素不为空,则要分情况
(i)如果是在JDK1.7,则首先会判断是否需要扩容,如果要扩容就进行扩容ÿ