在《Core Java Volume1》一书中有一个警告,它说:
谢谢。
这到底是什么意思?为什么1在左移35位后变成了8而不是0?注意:移位运算符的右侧参数对32取模(除非左侧是long类型,此时右侧对64取模)。例如,1 << 35的值与1 << 3或8相同。
谢谢。
这到底是什么意思?为什么1在左移35位后变成了8而不是0?注意:移位运算符的右侧参数对32取模(除非左侧是long类型,此时右侧对64取模)。例如,1 << 35的值与1 << 3或8相同。
模32取余(基本层面上)意味着你不断地减去32,直到得到一个介于0和31之间的数。
换句话说:
actualValue = givenValue % 32;
原因是因为将一个32位的值向左(或向右)移动32位几乎没有意义,因为这将总是得到零(因为你正在一侧移出位并在另一侧移入零 - 对32位值进行这样的操作无论最初的值如何,结果都会是零)。
因此,对于Java中的整数(32位),31是合理的限制。对于长整型(64位),63是合理的限制。
在您提供的示例中,1 << 35
将移位值从35减少到3(因为35%32 == 3
),而1 << 3是8:
Binary
0000 0001 (1 << 0) == 1
0000 0010 (1 << 1) == 2
0000 0100 (1 << 2) == 4
0000 1000 (1 << 3) == 8
||||
|||+--- 1
||+---- 2
|+----- 4
+------ 8
(n<<d)
等同于(n<<(d%32))
,其中n
是int类型,(n<<d)
等同于(n<<(d%64))
,其中n
是long类型。1<<35
相当于1<<(35%32)
,即1<<3=8
。a << b
等同于
a << (b & 31)
对于int类型而言,两者的区别在于 -1 % 32 的结果是 -1,而 -1 & 31 的结果是 31,1 << -1 == 0x80000000
这种行为在JLS 15.19中有定义。
如果左操作数提升后的类型为int,则只使用右操作数的最低5位作为移位距离。就好像右操作数被位逻辑与运算符&(§15.22.1)与掩码值0x1f(0b11111)进行按位与运算一样。实际使用的移位距离因此总是在0到31之间,包括0和31在内。
如果左操作数提升后的类型为long,则只使用右操作数的最低6位作为移位距离。就好像右操作数被位逻辑与运算符&(§15.22.1)与掩码值0x3f(0b111111)进行按位与运算一样。实际使用的移位距离因此总是在0到63之间,包括0和63在内。