java.util.IdentityHashMap#hash(Object x, int length)为什么总是返回2的倍数?
昨天在各个群里转悠的时候,有人问出这么一个问题?
问:这个方法为什么一直是2的倍数?
然后,他就自己给出了答案,一番操作猛如虎:
我这种菜鸟只看得一脸膜拜,满头问号,所以赶紧回去补基础……
1.h右移一位减去h右移八位,二进制的最后一位肯定是0
让我们过一遍代码:
这个identityHashCode 是个本地方法
反正是返回了一个对象的哈希码,返回值是int,可以进行位运算的操作。
(h << 1) - (h << 8)
<< 其实是左移,可能是他口误,表示的意思其实很直观,就是二进制的数字(位运算都是使用的二进制)向左移位,举个例子:
对数字5进行左移操作
5 << 1 = 10
5 << 2 = 20
5 << 3 = 40
5 << 4 = 80
怎么算的呢?
首先要先理解一个概念,二进制和十进制的互相转化
1.十进制转二进制,采用 除2取余 倒排的计算方式,例如:
对十进制 5 转 二进制
2.二进制转十进制,按第几位 取2的次方相加
101 个位是1(0次方),十位是0(1次方),百位是1(2次方)
1*2^2 + 0*2^1 + 1*2^0 = 4 + 0 + 1 = 5
好,再看下 << 的作用,是对左侧数字的二进制数进行左移操作,不论正负,都补零。
eg:5 << 1 = 10
101 -> 5
1010 -> 10
解释:
把101 左移一位并补零,是1010
1010 = 1*2^3 + 0*2^2 + 1*2^1 + 0*2^0 = 8 + 0 + 2 + 0 = 10
如果 h = 5,
那么h<<1 = 5 * 2^1 = 10,h << 8 = 5 * 2^8 = 1280
10-1280 = -1270
是一个负数,当然是一个负数,但是这个不是关键。关键是:
二进制的最后一位肯定是0 这句话,他从什么地方确信 (h << 1) - h << 8 的二进制值的最后一位肯定是0呢?
思考一秒,来了:
想一想,二进制的最低位是0的数是什么数?偶数!
偶数 - 偶数 = ?
偶数!
偶数的最低位是什么?
0
所以:
左移补零,最低位为零的必然是偶数,偶数减偶数还是偶数。最后一位肯定是0。
& 按位与 , 只有都是 1的时候才是 1,否则 是 0。
(h << 1) - (h << 8) & length -1 如果要返回偶数,最低位肯定是0, & 如果有一个是 0 那就是 0了,所以,到这里,已经可以确定,java.util.IdentityHashMap#hash(Object x, int length) 这个方法肯定会返回2的倍数,也就是偶数。
所以,问,为什么总是返回2的倍数?一句话说明:
(左移 - 左移) 与 (不论什么数) ,左侧,总是偶数,所以,总的结果也总是返回偶数。