开门见山,直接开始
HashMap解决了什么问题?
HashMap解决了插入与查找的效率问题,内部实现是通过数组和链表组合实现
HashMap如何确定数组大小
结论,根据传入的size大小,计算下一个最接近传入size大小的2的n次方(可能是size本身),例如,传入size为15,真实size为2的四次方16,代码如下:
/**
* Returns a power of two size for the given target capacity.
*/
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;
}
代码流程:
通过减1后进行右移操作,可以将数据的最高位1之后数据全部置1,对结果进行边界判断,如非负数或者超过int大值,则+1就可获取最接近(包括本身)输入size的下一个2的n次方
几步右移操作为了将最高位1之后的所有位数置为1
例如输入size 为15 ,减一操作后为n为14,二进制数据为0000 0000 0000 1110
右移1位或上本身,.得出n=0000 0000 0000 1111 ,实际上已经得出结果,后面操作不影响,其他32位数字类似
疑问一: 为什么要-1?
结论: 因为tableSizeFor是为了计算出下一个2的n次方数字,结果大于等于当前传入值,比如传入8,如不减一操作最后计算结果为16,显然不行
疑问二:为什么size要2的n次方:?
结论:一是为了减少hash碰撞,二是为了更高效的计算key在数组中的位置
疑问二;为什么要选择这种方式计算2的n次方
结论:cpu计算中,加减乘除的效率没有移位操作快,移位操作可以获得最高效率
HashMap 如何计算hash?
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
代码很简单,直接对key的hashcode和key的hashcode右移16位进行异或运算
疑问一: 为什么要右移16位?
结论:为了使hashcode的高位16位也能参与hash运算,增大散列程度,减少hash冲突
HashMap如何确定元素在数组中的位置
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V