【java解惑】移位运算符规则

    如下代码:

public class Example027 {

	public static void main(String[] args) {
		int i = 0;
		while (-1 << 32 != 0) {
			i++;
		}
		System.out.println(i);
	}
}

    结果说明:

    将上述程序放到eclipse中,在输出行会有提示“Unreachable code”。也就是while循环是死循环无法退出。

    结果分析:

    Java 使用的是基于 2 的补码的二进制算术运算,因此-1 在任何有符号的整数类型中(byte、short、int 或 long)的表示都是所有的位都为1。

    常量-1 是所有 32 位都被置位的 int 数值(0xffffffff)。左移操作符将 0 移入到由移位所空出的右边的最低位,因此表达式(-1 << i)将 i 最右边的位设置为 0,并保持其余的 32 - i 位为 1。很明显,这个循环将完成 32 次迭代,因为-1 << i 对任何小于 32 的 i 来说都不等于 0。你可能期望终止条件测试在 i 等于32 时返回 false,从而使程序打印 32,但是它打印的并不是32。 实际上,它不会打印任何东西,而是进入了一个无限循环。

问题在于(-1 << 32)等于-1 而不是 0,因为移位操作符只使用其右操作数的低5 位作为移位长度。或者是低 6 位,如果其左操作数是一个 long 类数值。

 这条规则作用于全部的三个移位操作符: <<、 >>和>>>。 移位长度总是介于 0 到31 之间,如果左操作数是 long 类型的,则介于 0 到 63 之间。这个长度是对 32取余的,如果左操作数是 long 类型的,则对 64 取余。如果试图对一个 int 数值移位 32 位,或者是对一个 long 数值移位 64 位,都只能返回这个数值自身的值。没有任何移位长度可以让一个 int 数值丢弃其所有的 32 位,或者是让一个 long 数值丢弃其所有的 64 位。

    一种可能的程序改进方案是,我们不是让-1 重复地移位不同的移位长度,而是将前一次移位操作的结果保存起来,并且让它在每一次迭代时都向左再移 1 位。下面这个版本的程序就可以打印出我们所期望的 32:

private static void shift() {
	int distance = 0;
	for (int val = -1; val != 0; val <<= 1)//左移32次后,var == 0
		distance++;
	System.out.println(distance);
}

很多程序员都希望具有负的移位长度的右移操作符可以起到左移操作符的作用,反之亦然。但是情

况并非如此。右移操作符总是起到右移的作用,而左移操作符也总是起到左移的作用。负的移位长度通过只保留低 5 位而剔除其他位的方式被转换成了正的移位长度(如果左操作数是 long 类型的,则保留低 6 位)。因此,如果要将一个 int数值左移,其移位长度为-1,那么移位的效果是它被左移了31位。

移位长度是对 32 取余的,或者如果左操作数是 long 类型的, 则对 64 取余。因此,使用任何移位操作符和移位长度,都不可能将一个数值的所有位全部移走。同时,我们也不可能用右移操作符来执行左移操作,反之亦然。如果可能的话,请使用常量的移位长度,如果移位长度不能设为常量,那么就要千万当心。


(注:本【java解惑】系列,均是博主阅读《java解惑》原书后,将原书上的讲解和例子部分改编,然后写成博文进行发布的。所有例子均亲自测试通过,并共享在github上。通过这些例子,激励自己,惠及他人。同时,本系列所有博文会同步发布在博主个人微信公众号(搜索“爱题猿”或者“ape_it”),方便大家阅读。如果文中有任何侵犯原作者权利的内容,请及时告知博主,以便及时删除;如果读者对文中的内容有异议或者问题,欢迎通过博客留言或者微信公众号留言等方式共同探讨。)

源代码地址:https://github.com/rocwinger/java-disabuse


时间: 2024-08-05 11:18:41

【java解惑】移位运算符规则的相关文章

理解java移位运算符

  移位运算符操作的对象就是二进制的位,可以单独用移位运算符来处理int型整数.  运算符       含义       例子       << 左移运算符,将运算符左边的对象向左移动运算符右边指定的位数(在低位补0) x<<3 >> "有符号"右移运算 符,将运算符左边的对象向右移动运算符右边指定的位数.使用符号扩展机制,也就是说,如果值为正,则在高位补0,如果值为负,则在高位补1. x>>3 >>> "无符

移位运算符(JAVA)

java中有三种移位运算符 <<      :     左移运算符,num << 1,相当于num乘以2 >>     :     右移运算符,num >> 1,相当于num除以2 >>>    :     无符号右移,忽略符号位,空位都以0补齐 1. 左移运算符 左移运算符<<使指定值的所有位都左移规定的次数.1)它的通用格式如下所示:value << numnum 指定要移位值value 移动的位数.左移的规则只

java移位运算符详解[转]

java移位运算符不外乎就这三种:<<(左移).>>(带符号右移)和>>>(无符号右移). 1. 左移运算符 左移运算符<<使指定值的所有位都左移规定的次数. 1)它的通用格式如下所示: value << num num 指定要移位值value 移动的位数. 左移的规则只记住一点:丢弃最高位,0补最低位 如果移动的位数超过了该类型的最大位数,那么编译器会对移动的位数取模.如对int型移动33位,实际上只移动了332=1位. 2)运算规则 按

java移位运算符详解

java移位运算符不外乎就这三种:<<(左移).>>(带符号右移)和>>>(无符号右移).1.左移运算符左移运算符<<使指定值的所有位都左移规定的次数.1)它的通用格式如下所示:value << numnum 指定要移位值value 移动的位数.左移的规则只记住一点:丢弃最高位,0补最低位如果移动的位数超过了该类型的最大位数,那么编译器会对移动的位数取模.如对int型移动33位,实际上只移动了332=1位. 2)运算规则按二进制形式把所有的

java中的移位运算符:&lt;&lt;,&gt;&gt;,&gt;&gt;&gt;总结

java中有三种移位运算符 <<      :     左移运算符,num << 1,相当于num乘以2 >>      :     右移运算符,num >> 1,相当于num除以2 >>>    :     无符号右移,忽略符号位,空位都以0补齐 下面来看看这些移位运算都是怎样使用的 1 /** 2 * 3 */ 4 package com.b510.test; 5 6 /** 7 * @author Jone Hongten 8 * @

JAVA移位运算符

java中有三种移位运算符(二进制) <<      :     左移运算符,num << 1,相当于num乘以2 >>      :     右移运算符,num >> 1,相当于num除以2 >>>    :     无符号右移,忽略符号位,空位都以0补齐

java中的移位运算符

java中有三种移位运算符 <<      :     左移运算符,num << 1,相当于num乘以2 >>      :     右移运算符,num >> 1,相当于num除以2 >>>    :     无符号右移,忽略符号位,空位都以0补齐 int number = -1; //原始数二进制 printInfo(number); number = number << 1; //左移一位 printInfo(number)

java中的基本运算符、取余、逻辑运算符、逻辑运算符、位运算符、移位运算符

注意事项: 常量在编译的时候会赋值,变量在运行的时候才在内存中分配空间赋值. 赋值运算符 += -+ *+ %= \= 在java编译器会进行强制类型转换 取余: 在java中做取余运算的是时候,结果的正负号是取决于被除数. 逻辑运算符&且 |或 !非 ^异或 &&短路与 ||短路或 位运算符:直接操作二进制位的. & (与) 6 & 3 = 2 0000 0110 可以把1看成true & 0000 0011 0看成false --------------

【java解惑】条件表达式结果类型规则

如下代码: public class Example008 { public static void main(String[] args) { char x = 'X'; int i = 0; System.out.println(true ? x : 65535); //1 System.out.println(true ? x : 65536); //2 System.out.println(true ? x : i); //3 System.out.println(false ? 0 :