JAVA的移位运算符有三种:
<< : 左移运算符,右端补零
>> : 右移运算符,左端补符号位
>>> : 无符号右移,左端补零
注意:
>>和>>>只对负数有区别, 因为整数符号位是0
并没有<<<运算符,因为左移时右端补零和<<一样
>>叫算术位移,左侧补符号位, >>>叫逻辑位移, 左侧补0
位移操作数字的补码, 因为计算机内以补码形式存储数字
>>,<<移位时不影响符号位 ,>>>移位影响符号位
int a=2;
System.out.println(a>>1);
System.out.println(a>>>1);
//结果是两个1
//说明对于正数>> 和 >>> 一样
int a=-1;
System.out.println(a>>1);
System.out.println(a>>>1);
//第一个输出:-1
//第二个输出:2147483647
可以看到上例int型的 -1 原码 是 1 00000000 00000000 00000000 0000001
如果是原码移位的话 -1>>1 后应该是 1 10000000 00000000 00000000 0000000=1073741824
原码-1>>>1 后应该时 1 00000000 00000000 00000000 0000000=-0
与输出不符,显然移位的并不是数字的原码而是补码:
数 | 原码 | 补码 | 操作 | 结果 |
-1 | 1 00000000 00000000 00000000 0000001 | 1 11111111 11111111 11111111 1111111 | >> | 1 11111111 11111111 11111111 1111111(这是补码) = -1 |
-1 | 1 00000000 00000000 00000000 0000001 | 1 11111111 11111111 11111111 1111111 | >>> | 0 11111111 11111111 11111111 1111111(这是原码)=2147483647 |
也就是说:
JAVA所有移位运算符直接操作补码
<<和>>运算符 不影响符号位, 从符号位后移位开始移位, >>左端补符号位 ,移位后把补码转换成原码输出
>>> 无视符号位(故而叫逻辑右移), 不分正负,把存储的数当作原码处理(即使存储是补码)符号为也会右移, 左端补零
再举个例子:
public static void main(String[] args)
{
int a=-1;
int b=-999;
int c=1;
int d=999;
System.out.println(a>>31);
System.out.println(b>>31);
System.out.println(c>>31);
System.out.println(d>>31);
}
//输出:
//-1
//-1
//0
//0
移位31位后数的补码只剩下 32位符号位全1 或全零 转回原码则是 -1 和0
因而>>31或者大于31时 原来是正数则等于0 负数则等于-1, 只与正负有关,与大小无关
这样可以达到判断正负的目的, 类似的也可以用>>>达到目的,如下例
public static void main(String[] args)
{
int a=-1;
int b=-999;
int c=1;
int d=999;
System.out.println(a>>>31);
System.out.println(b>>>31);
System.out.println(c>>>31);
System.out.println(d>>>31);
}
//输出:
//1
//1
//0
//0
逻辑右移>>>31位时把符号位移到了最后, 输出也就是1或0 与大小无关
可以这样判断符号位是正是负, 是否位0