HashMap 底层原理面试题 总结
Q0:HashMap是如何定位下标的?
A:1、获取key的hashCode值 h,获取h的无符号位移16的结果
2、1中的结果做异或运算
3、2中重新计算hash值与数组长度n-1做与运算
// 计算key的hash值
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
// 计算数组下标 数组长度为2的倍数
(n - 1) & hash
Q1:HashMap由什么组成?
A:数组+链表,jdk1.8以后又加了红黑树,当链表节点个数大于等于8(m默认值)以后,开始使用红黑树,使用红黑树一个综合取优的选择,相对于其他数据结构,红黑树的查询和插入效率都比较高。而当红黑树的节点个数小于6个(默认值)以后,又开始使用链表。这两个阈值为什么不相同呢?主要是为了防止出现节点个数频繁在一个相同的数值来回切换;
举个栗子:现在HashMap新增元素链表的节点个数是9,开始变成红黑树,然后又删除元素,使红黑树节点个数又变成8,如果阈值不变就会转变成链表,如果再新增元素节点大小又变成9,就又得变成红黑树,这样的情况消耗严重浪费,因此干脆错开两个阈值的大小,使得变成红黑树后“不那么容易”就需要变回链表,同样,使得变成链表后,“不那么容易”就需要变回红黑树。
Q2:Java的HashMap为什么不用取余的方式存储数据?
A:实际上HashMap的indexFor方法用的是跟HashMap的容量-1做按位与操作,而不是%求余。(这里有个硬性要求,容量必须是2的指数倍,原因参考Q6)
int hash = key.hashCode(); // 这个hashCode方法这里不详述,只要理解每个key的hash是一个固定的int值
int index = hash %(