在java中,位移符号 ( <<、 >> 和 >>> ) 是使用频率相对不太高的运算符号。不过,在一些特定的程序语境中,这些符号相当的有用,例如在JavaME程序中做数据的乘除运算,很多时候就以 << 和 >> 来书写代码。
Lucio童鞋发了几行关于处理RGB色值转换的代码和我讨论,大致的问题是将int类型左移64位和左移128位应该得到什么结果。结果我俩在这上头遇到了不解的谜,大意如下:
int d = (1 << 32), e = (1 << 64), f = (1 << 128);
问这些数的值到底几何,很显然,第一行的a = 2^3 = 8,b = 2^8 = 256, c = 2^31 = 2147483648。但是第二行怎么算呢?java中的int类型是32bit,第二行中左移的位数都超过了这个范围,我俩都直接觉得 d == e == f == 0。However, 在运行过实际程序之后,结果出乎意料之外……
实际执行的时候,d == e == f == 1。这究竟是为什么呢?这时候就要靠猛击JLS来寻找神谕了……(还用不着直接骚扰Gosling大神)。在 圣经 JLS的第十五节第十九条中给出了明确的解释:
If the promoted type of the left-hand operand is int, only the five lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x1f. The shift distance actually used is therefore always in the range 0 to 31, inclusive.
If the promoted type of the left-hand operand is long, then only the six lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x3f. The shift distance actually used is therefore always in the range 0 to 63, inclusive.
... ...
原来位移运算右侧的操作数会先被截取有效的数值。当左侧是int类型的值时,右侧的shift distance仅保留最低5位,也就是说它的有效值是介于0-31之间。所以这就可以解释上述例子中d,e,f的值为什么都是1了—— 32, 64, 128 都先和 0x1f 做了 bitwise-AND 运算,都等于0,于是 (1 << 32) == (1 << 64) == (1 << 128) == (1 << 0) == 1
所以,想当然地以为位移就直接将数据都移到左侧,全部清零是不对滴~
评论