位运算是直接对二进制进行运算。
位运算的参与都是整数,在左移或者右移的过程中,需要补0。
左移无论是负数还是正数,都是在低位补0,左移几位,就补几个0。
右移有正负数之分,正数在高位补0,负数则在高位补1。同样的道理,右移几位,就补几个。
无符号右移,无论是正数还是负数,都在高位补0。
位运算符涉及原码、反码及补码,先来科普一下什么是原码、反码、补码。
原码:把一个整数转换成二进制的形式,转换之后的二进制就是该整数对应的原码。
反码:分正数和负数。正数反码和原码相同;负数反码就是将原码中除符号位以外的其它位进行取反,也就是0变成1,1变成0。
补码:这个也分正数和负数。正数补码和原码也是相同的;负数补码则是对反码加1。
计算机中,一个整数占4个字节,一个字节表示8位,4*8就是32位。在计算机中,它们以补码的形式进行存储。
1、左移(<<)
System.out.println(3 << 2); //答案为12
System.out.println(-3 << 2); //答案为-12
3左移2位计算过程:
0 0011----补码(与原码相同)
0 1100----左移两位,低位补0
结果为12
-3左移2位计算过程:
1 0011----原码
1 1101----补码(原码到补码,取反+1)
1 0100----左移两位,低位补0
1 1100----对应原码(补码到原码,-1再取反)
结果为-12
2、右移(>>)
System.out.println(3 >> 1); //答案为1
System.out.println(-3 >> 1); //答案为-2
3右移1位计算过程:
0 0011----补码(与原码相同)
0 0001----右移1位,高位补0
结果为1
-3右移1位计算过程:
1 0011----原码
1 1101----补码(原码到补码,取反+1)
1 1110----右移一位,高位补1
1 0010----对应原码(补码到原码,-1再取反)
结果为-2
3、无符号右移(>>>)
无符号右移与右移不一样。在执行右移操作时,若参与运算的为正数,则在高位补0;若为负数,则在高位补1。而无符号右移,无论参与运算的是正数还是负数,在执行运算时,都在高位补0。
System.out.println(3 >>> 1); //答案为1
System.out.println(-3 >>> 1); //答案为2147483646
3无符号右移1位计算过程:
0000 0000 0000 0000 0000 0000 0000 0011----补码(与原码相同)
0000 0000 0000 0000 0000 0000 0000 0001----右移1位,高位补0
结果为1
-3无符号右移1位计算过程:
1000 0000 0000 0000 0000 0000 0000 0011----原码
1111 1111 1111 1111 1111 1111 1111 1101----补码(原码到补码,取反+1)
0111 1111 1111 1111 1111 1111 1111 1110----右移一位,高位补0
0111 1111 1111 1111 1111 1111 1111 0010----对应原码(补码到原码,-1再取反)
结果为2147483646
4、与运算(&)
两位同时为1,结果才为1
System.out.println(6 & 3); //答案为2
System.out.println(-6 & 3); //答案为2
计算过程:
0 0110----6补码 1 1010---- -6补码
0 0011----3补码 0 0011---- 3补码
0 0010----结果 0 0010---- 结果
答案均为2
5、或运算(|)
只要有一位1,结果就为1。
System.out.println(6 | 3); //答案为7
System.out.println(-6 | 3); //答案为-5
计算过程:
0 0110----6补码 1 1010---- -6补码
0 0011----3补码 0 0011----3补码
0 0111----结果 1 1011-->-1再取反得到结果为-->1 0101
答案分别为7和-5
6、异或运算(^)
两位相同时为0,不同时为1。
System.out.println(6 ^ 3); //答案为5
System.out.println(-6 ^ 3); //答案为-7
计算过程:
0 0110----6补码 1 1010---- -6补码
0 0011----3补码 0 0011---- 3补码
0 0101----结果 1 1001-->-1再取反得到结果为-->1 0111
答案分别为5和-7
7、按位取反(~)
对数据的每个二进制位取反,即0变成1,1变成0。
System.out.println(~ 6); //答案为-7
System.out.println(~ -6); //答案为5
计算过程:
6 -->原码:0 0110-->补码:0 0110-->按位取反:1 1001-->对应原码:1 0111(-1再取反)
-6-->原码:1 0110-->补码:1 1001-->按位取反:0 0110
结果为-7和5。