1. 无符号右移   >>>  或 >>> =

无符号右移(>>>)跟右移(>>)运算符不一样。

右移不改变数的正负。

对于一个正数,无符号右移不会变成负数(相当于除以1再取整);但是对于一个负数,无符号右移会将负数变成正数;


int i = -4;
System.out.printf(“%-10d %32s
“, i, Integer.toBinaryString(i));
i >>>= 1;  // 无符号右移1位
System.out.printf(“%-10d %32s
“, i, Integer.toBinaryString(i));

i >>>= 1;
System.out.printf(“%-10d %32s
“, i, Integer.toBinaryString(i));

输出:

-4                  11111111111111111111111111111100       //负数在java中以补码形式存储,-4的补码表示是11111111111111111111111111111100
2147483646     1111111111111111111111111111110       //无符号右移1位,-4的补码表示的符号位也右移了1位,导致符号位变成0,成为正数
1073741822       111111111111111111111111111110       //再无符号右移1位

int i = 15;
System.out.printf("%-10d %32s
", i, Integer.toBinaryString(i));
i >>>= 1;
System.out.printf("%-10d %32s
", i, Integer.toBinaryString(i));

输出:

15     1111  
7         111  //对正数进行无符号右移,高位补0

int i = 0x80000000;
System.out.printf("%-12d %32s
", i, Integer.toBinaryString(i));
i >>>= 1;
System.out.printf("%-12d %32s
", i, Integer.toBinaryString(i));
i >>>= 1;
System.out.printf("%-12d %32s
", i, Integer.toBinaryString(i));

输出:

-2147483648 10000000000000000000000000000000       //最小负数的补码表示
1073741824    1000000000000000000000000000000       //符号位右移一位,变成正数
536870912        100000000000000000000000000000

总结:

无符号右移的叫法,容易让人误解。虽然叫作无符号右移运算,让人第一印象以为是不对符号位进行移位,其实却是连同符号位一起右移;

对复数进行无符号右移,符号位也一起右移,将会变成正数;

对正数进行若干次无符号右移,得到的永远都是正数或0;

2. 左移位运算  <<  或  <<=

跟右移运算不同的是,无符号左移和左移是一样的。因此java没有无符号左移运算。(<<<和<<<=将报错)

因为无右移运算需要考虑符号位的右移,而符号位只存在于二进制表示的最左边,最右边没有。

所以不用区分无符号左移和左移运算。

int i = 0x80000000;
System.out.printf("%-12d %32s
", i, Integer.toBinaryString(i));
i <<= 1;
System.out.printf("%-12d %32s
", i, Integer.toBinaryString(i));
i >>= 1;
System.out.printf("%-12d %32s
", i, Integer.toBinaryString(i));

输出:

-2147483648 10000000000000000000000000000000    
0                                                                        0    //最小负数左移1位,将变成0
0                                                                        0