jdk1.8查看扩容实现中有段:
(e.hash & oldCap) == 0
以下实例中默认长度为16
网上很多解释这段代码的原因,都知道是为了减少数据存储下标运算,但好像没有十分详细的解释,下面将以实例做个详细讲解,以此做个学习记录。
假设我现在创建了一个hashmap对象,它的key是education,它的hashcode码是 -1147692044
经过源码中:(h = key.hashCode()) ^ (h >>> 16) 这段公式的计算后为:-1147723677,看的出来值为负整数,这里要注意源码中用到的换位&、^等运算符都是基于二进制数进行操作,正数与负数转二进制又存在补码的差别,正数补码只是以0补齐高位,达到int的长度4字节,32位即可,但负数的补码是除了符号位其他取反,末位加1的限制。
按以上要求对-1147723677进行转换后的二进制为:10111011100101110010000001100011
因为-1147723677未补码前是:0100 0100 0110 1000 1101 1111 1001 1101。
讲以上二进制值套入(e.hash & oldCap) == 0公式中计算可以得出值为0,拆解后表达为:
10111011100101110010000001100011 & 16(10000),其实参与计算的只是oldCap值的高位,逢1取1,得出计算后的值为0,即该下标的值不用重新分配存储。
然后我们再换个key的名字,key的名字为name,hashcode值为:3373707,参与以下
(h = key.hashCode()) ^ (h >>> 16) 计算后的值为:3373752,转换为二进制后的值为:
0000 0000 0011 0011 0111 1010 1011 1000,参与(e.hash & oldCap) == 0计算后的值为:16,
拆解公式表示为:
0000 0000 0011 0011 0111 1010 1011 1000 & 00000000 00000000 00000000 00010000,比的是hash值与oldCap值的最高位是否相等,如果相等就大于0,不相等就等于0,这样就简单的将数组扩容中数据转移分为不重新计算下标存储与重新计算下标存储两类,减少了数据运算成本,提高了效率,这样的拆解描述应该是说明白了其中的原因了。