Java 中有三种移位运算符,分别是:
<<
:左移运算符>>
:带符号右移>>>
:无符号右移
那么这个移位运算符该怎么理解呢?顾名思义,移位移位,就是移动位置。那么问题来了,既然是移动位置,那么移位运算符移动的是谁的位置,怎么移?我们写个程序测试一下。
public class Main {
public static void main(String[] args) {
System.out.println("----------- 初始值 -----------");
int number = 10;
System.out.println("十进制:" + number + "\t二进制:" + Integer.toBinaryString(number));
leftShift(number);
rightShift(number);
unsignedRightShift(number);
}
public static void leftShift(int number) {
System.out.println("----------- 左移 -----------");
number = number << 1;
System.out.println("十进制:" + number + "\t二进制:" + Integer.toBinaryString(number));
}
public static void rightShift(int number) {
System.out.println("----------- 带符号右移 -----------");
number = number >> 1;
System.out.println("十进制:" + number + "\t二进制:" + Integer.toBinaryString(number));
}
public static void unsignedRightShift(int number) {
System.out.println("----------- 无符号右移 -----------");
number = number >>> 1;
System.out.println("十进制:" + number + "\t二进制:" + Integer.toBinaryString(number));
}
}
上述程序执行后的结果如下:
----------- 初始值 -----------
十进制:10 二进制:1010
----------- 左移 -----------
十进制:20 二进制:10100
----------- 带符号右移 -----------
十进制:5 二进制:101
----------- 无符号右移 -----------
十进制:5 二进制:101
观察结果我们发现,实际上移位运算符移动的是二进制数值的位置。
以上述结果数据为例,初始值 10
的二进制为 1010
,使用 10 << 1
向左移动一位后,即整串 1010
向左移动,然后在右端补 0
,最后结果即为 10100
。
但是,右移就显得复杂了些。我们注意到,Java 中右移分为带符号右移和无符号右移,那么两者有什么区别呢?
带符号右移在向右移位后,会在左侧补上原最高位的值。
无符号右移在向右移位后,会在左侧补上直接补上 0
。
在上面的例子里,由于初始值 10
的二进制最高位为 0
,所以无论是使用带符号右移还是无符号右移,二进制 1010
都会向右移动一位,然后在左端补 0
,最后结果即为 101
。
我们现在换个初始值,使其二进制首位为 1
,即可观察到带符号右移和无符号右移的差异。
假设初始值为 -10
,运行上面的程序,得到以下结果:
----------- 初始值 -----------
十进制:-10 二进制:11111111111111111111111111110110
----------- 左移 -----------
十进制:-20 二进制:11111111111111111111111111101100
----------- 带符号右移 -----------
十进制:-5 二进制:11111111111111111111111111111011
----------- 无符号右移 -----------
十进制:2147483643 二进制:1111111111111111111111111111011
乍一看好像没什么区别,但是把右移后的二进制值复制到一起,会发现有趣的事。
11111111111111111111111111111011
1111111111111111111111111111011
我们发现,无符号右移后的二进制值少了一位。实际上是由于 toBinaryString
没有把二进制前的 0
打印出来而已,我们现在把这个 0
补上,再比较一下。
11111111111111111111111111111011
01111111111111111111111111111011
确实如上面所说,带符号右移和无符号右移的区别就在于右移后左侧是补 0
还是补最高位的值。
现在,我们可以对上面所述内容做个总结:
<<
:表示左移运算符,作用是将二进制数左移 N 位,并在右侧补齐0
>>
:表示带符号右移,作用是将二进制数右移 N 位,并在左侧补齐最高位对应的值>>>
:表示无符号右移,作用是将二进制数右移 N 位,并在左侧补齐0