前言:HashMap是java工程师在面试过程中,碰到的概率极大的一道题,很大一部分人都是看了一些博客,记住一些答案,但是深究往往无法接招,本文就来扒一扒hashMap面试常见的点及源码分析。
推荐分析目前为止个人看过的分析hashMap比较好的文章。
Java 8系列之重新认识HashMap
没有阅读过的同学,可以先看一下这篇文章,对于hashMap的设计及原理有一个大概的了解,一遍不行;读两遍。
1、hashMap中提到了“当链表长度大于8时,链表默认转化为红黑树”,为什么链表长度为8的时候转化呢?
答:如果节点数量比较少遍历链表速度也很快,没必要转成树,而且树还要多占空间,那么如何定一个临界值呢?根据泊松分布节点相同次数超过8个节点的概率大概是百万分之一,再记录增加概率也不会降低太多,最终得到一个临界值是8,也就是说插入到hashMap中节点,真正需要转化为红黑树的其实是很少的情况。
我们可以看一下源码做的统计:
*
* 0: 0.60653066
* 1: 0.30326533
* 2: 0.07581633
* 3: 0.01263606
* 4: 0.00157952
* 5: 0.00015795
* 6: 0.00001316
* 7: 0.00000094
* 8: 0.00000006
* more: less than 1 in ten million
*
2、我们知道随着同一个槽中节点的减少,红黑树可能会退化成链表,jdk中定义了该值为6,为什么定义为6,而不是7呢?
/**
* 当红黑树元素个数小于6的时候,会从新退化为链表。为什么?效率。
*/
static final int UNTREEIFY_THRESHOLD = 6;
答:链表查找的时间复杂度= O ( n / 2 ) O(n/2) O(n/2),红黑树的查找时间复杂度是 O ( l o g n ) O(logn) O(logn),当n=8,红黑树的时间是2,链表的时间是4,红黑树优于链表。当n=6,链表查询时间是3,红黑树是2.585,红黑树基本已经没什么优势了,其实对于7也没什么优势,但是如果选择7会导致链化和树化频繁切换,所以间隔调两个元素。5、6同理,但是总得敲定一个数呀。
3、为什么hashMap在扩容的时候,容量大小必须是
2
n
2^n
2n呢?
HashMap采用这种非常规设计,主要是为了在取模和扩容时做优化,同时为了减少冲突,HashMap定位哈希桶索引位置时,也加入了高位参与运算的过程。
扩容的时候,可以做到元素的新位置要么是在原位置,要么是在原位置再移动2次幂的位置。
hash值新增的那个bit是1还是0就好了,是0的话索引没变,是1的话索引变成“原索引+oldCap”