先看下hash(Object key)方法,详细大家基本都能看懂,但是知道这一步(h = key.hashCode()) ^ (h >>> 16)原因的人很少。
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
这里主要理解一下 (h = key.hashCode()) ^ (h >>> 16) 这一段代码
hash 算法的精髓都在这里面
1.key.hashCode() 获取hash 值,为什么不用hashCode直接比较呢?
答: 这里就要说一下HashMap 默认为什么是16位 ,hashCode 是int 类型的, int 类型是16位的. <br/>而为什么不用hashCode 直接比较,是因为hashCode 16位,而16位的数字散列的肯定不如32位的二进制散列的均匀,更容易发生hash碰撞所以不用hashCode直接比较
2.从代码中我们可以明显的知道高于16位的通过 ^ (异或) 右移16位来得到比较的值,但是小于16位的呢?
答: 简单的从上面代码可以得知, 如果是大于16位得到hashCode,然后右移16位,其实比较的也就是从左往右的16位数字. 当时我就有个困惑 小于16位呢?(这也是自己对^异或运算掌握的不够好)其实异或后得到的还是它本身
PS: 下面是对我自己的解释:
异或运算符(^)
参加运算的两个数据,按二进制位进行“异或”运算。
运算规则:0^0=0; 0^1=1; 1^0=1; 1^1=0;
即:参加运算的两个对象,如果两个相应位为“异”(值不同),则该位结果为1,否则为0。
首先右边运算得到的是32位全为0, 右边是本身,而 1^0=1;的情况还是1 所以得到的结果还是它本身
3.为什么加载因子是0.75呢?
答: 其实是通过泊松分布来计算的.在设置初始容量时应该考虑到映射中所需的条目数及其加载因子,以便最大限度地减少扩容rehash操作次数,所以,一般在使用HashMap时建议根据预估值设置初始容量,以便减少扩容操作。
选择0.75作为默认的加载因子,完全是时间和空间成本上寻求的一种折衷选择。
在维基百科中的解释是这样的:
对于开放定址法,加载因子是特别重要因素,应严格限制在0.7-0.8以下。超过0.8,查表时的CPU缓存不命中(cache missing)按照指数曲线上升。因此,一些采用开放定址法的hash库,如Java的系统库限制了加载因子为0.75,超过此值将resize散列表。