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的倍数?一句话说明:

(左移 - 左移) 与 (不论什么数) ,左侧,总是偶数,所以,总的结果也总是返回偶数。

若有错漏之处,欢迎指正!

posted @ 2020-06-07 18:04  大水煮鱼  阅读(170)  评论(0编辑  收藏  举报