1. 无符号右移 >>> 或 >>> =
无符号右移(>>>)跟右移(>>)运算符不一样。
右移不改变数的正负。
对于一个正数,无符号右移不会变成负数(相当于除以1再取整);但是对于一个负数,无符号右移会将负数变成正数;
int i = -4;
System.out.printf("%-10d %32s\n", i, Integer.toBinaryString(i));
i >>>= 1; // 无符号右移1位
System.out.printf("%-10d %32s\n", i, Integer.toBinaryString(i));
i >>>= 1;
System.out.printf("%-10d %32s\n", 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\n", i, Integer.toBinaryString(i)); i >>>= 1; System.out.printf("%-10d %32s\n", i, Integer.toBinaryString(i));
输出:
15 1111
7 111 //对正数进行无符号右移,高位补0
int i = 0x80000000; System.out.printf("%-12d %32s\n", i, Integer.toBinaryString(i)); i >>>= 1; System.out.printf("%-12d %32s\n", i, Integer.toBinaryString(i)); i >>>= 1; System.out.printf("%-12d %32s\n", i, Integer.toBinaryString(i));
输出:
-2147483648 10000000000000000000000000000000 //最小负数的补码表示
1073741824 1000000000000000000000000000000 //符号位右移一位,变成正数
536870912 100000000000000000000000000000
总结:
无符号右移的叫法,容易让人误解。虽然叫作无符号右移运算,让人第一印象以为是不对符号位进行移位,其实却是连同符号位一起右移;
对复数进行无符号右移,符号位也一起右移,将会变成正数;
对正数进行若干次无符号右移,得到的永远都是正数或0;
2. 左移位运算 << 或 <<=
跟右移运算不同的是,无符号左移和左移是一样的。因此java没有无符号左移运算。(<<<和<<<=将报错)
因为无右移运算需要考虑符号位的右移,而符号位只存在于二进制表示的最左边,最右边没有。
所以不用区分无符号左移和左移运算。
int i = 0x80000000; System.out.printf("%-12d %32s\n", i, Integer.toBinaryString(i)); i <<= 1; System.out.printf("%-12d %32s\n", i, Integer.toBinaryString(i)); i >>= 1; System.out.printf("%-12d %32s\n", i, Integer.toBinaryString(i));
输出:
-2147483648 10000000000000000000000000000000
0 0 //最小负数左移1位,将变成0
0 0