在hashmap中是通过如下的算法来调整table的长度的,下面的算法的最终结果是构建一个2的幂次数。
static final int MAXIMUM_CAPACITY = 1 << 30; //减一之后最长为30位1
static final int tableSizeFor(int cap) {
int n = cap - 1; //防止现在就是2的幂次,如果不减,经过下面的算法会把最高位后面的都置位1,再加1则相当于将当前的数值乘2
n |= n >>> 1; // 高位右移1位,保障高位和第二高位都为11
n |= n >>> 2; //高两位右移2位,保障高4位都为1
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16; //保障最高的可达32位都为1
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
在HashMap中取一个key的hash值是如下操作的
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
原来的原来的hash值的高16位保持不变,低16位进行了异或操作,因为在hashmap存放数据的table中,放置数据的index的取值算法如下
(n - 1) & hash
n为table的长度,由于table的是2的幂次,减去1(即为table中可存放的最大的index),则数据存储的是全为1,最长为30位,再和hash与操作,则hash后面的长度会被取出来被均匀放到这个固定长度的数组中来,这样就容易造成只有hash的低位被取出来做index,很容易碰撞,如果先将hash的低位和高位异或处理,利用了hash的高位数据,也让低位的数据更加随机,减少碰撞的几率。