在面试的时候、面试官经常会问HashMap的问题。
例如HashMap的初始化大小为什么是16?
为什么扩容是原来的2的n次方倍?
为什么要引入红黑树 ,为什么不用完全平衡二叉树?
为什么链表长度达到8的时候才转化为红黑树、为什么不是16? (涉及到离散数据、概率论、泊松分布感兴趣的小伙伴可以看看源码)?
还有一个问题 就是如果我new一个HashMap 例如 Map map = new HashMap(3 );
我通过构造函数制定了HashMap的长度 这时候Java代码会初始化多大容量的HashMap给我呢?是 3 、是 4 、还是16 ?
通过阅读源码我们看到这一段代码 ,乍一看还是蛮懵的。顺手在纸上画了一下、发现是要返回大于cap的最小2次方幂。
| 是按位或、>>> 是无符号右移,那这一段代码为什么要这样写呢?
cap - 1 的目的 防止cap 原本就是 2的次方幂。
n 右移后再与按位或目的是 将低位都置为1;
n + 1 后就是大于cap的最小2次方幂。
static final int tableSizeFor(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
cap = 3
0000 0000 0000 0000 0000 0000 0000 0011
n = cap - 1
0000 0000 0000 0000 0000 0000 0000 0010
n >>> 1
0000 0000 0000 0000 0000 0000 0000 0001
n | n >>> 1
0000 0000 0000 0000 0000 0000 0000 0011
n >>> 2
0000 0000 0000 0000 0000 0000 0000 0000
n | n >>> 2
0000 0000 0000 0000 0000 0000 0000 0011
....
n = 3
n = n + 1
n = 4
cap = 30
0000 0000 0000 0000 0000 0000 0001 1110
n = cap - 1
0000 0000 0000 0000 0000 0000 0001 1101
n >>> 1
0000 0000 0000 0000 0000 0000 0000 0111
n | n >>> 1
0000 0000 0000 0000 0000 0000 0001 1111
n >>> 2
0000 0000 0000 0000 0000 0000 0000 0111
n | n >>> 2
0000 0000 0000 0000 0000 0000 0001 1111
n >>> 4
0000 0000 0000 0000 0000 0000 0000 0001
n | n >>> 4
0000 0000 0000 0000 0000 0000 0001 1111
...
n = 31
n = n + 1 = 32