为什么要使用位运算符
对于编程语言来说,位运算是逃不过的一个重点。对于没有系统学习过位运算的人来说,使用位运算去计算和实现一些业务的时候是非常折磨的。但是对于计算机底层,平常的一些算数运算符(+-*/%)效率是很低的,而使用位运算符直接对二进制进行操作,不仅让计算机很好辨别,也会大大提高效率。
位逻辑运算符
位逻辑运算符主要包含四个:
-
按位与运算符:
&
-
按位或运算符:
|
-
按位亦或运算符:
^
-
按位取反运算符:
~
按位与运算符
按位与运算符符号为&
,运算符规则为:参与运算的数字,低位对齐,高位不足的补零,如果对应的二进制位同时为 1,那么计算结果才为 1,否则为 0。另外,任何数与 0 进行按位与运算,其结果都为 0。
即 1 & 1 = 1 ,1 & 0 = 0,0 & 1 = 0,0 & 0 = 0
通过与1进行按位与,可以用来判断数的奇偶性,因为1的二进制表达为0001,结合运算规则可以达到效果。
public boolean isOdd(int a){
if((a&1) != 1){ //是偶数
return true;
}
return false;
}
按位或运算符
按位或运算符的符号为|
,运算符规则为:参与运算的数字,低位对齐,高位不足的补零。如果对应的二进制位只要有一个为 1,那么结果就为 1;如果对应的二进制位都为 0,结果才为 0。
即 1 | 1 = 1 ,1 | 0 = 1,0 | 1 = 1,0 | 0 = 0
按位亦或运算符
按位亦或运算符的符号为^
,其运算规则是:参与运算的数字,低位对齐,高位不足的补零,如果对应的二进制位相同(同时为 0 或同时为 1)时,结果为 0;如果对应的二进制位不相同,结果则为 1。
即 1 ^ 1 = 0 ,1 ^ 0 = 1,0 ^ 1 = 1,0 ^ 0 = 0
按位取反运算符
按位取反运算符的符号为~,其运算规则是:只对一个操作数进行运算,将操作数二进制中的 1 改为 0,0 改为 1。
即 ~ 0 = 1,~ 1 = 0
位移运算符
位移运算符用来将操作数向某个方向(向左或者右)移动指定的二进制位数。
左位移运算符
左位移运算符符号为<<
,其运算规则是:按二进制形式把所有的数字向左移动对应的位数,高位移出(舍弃),低位的空位补零。
下面以11左移1位为例。
从图中可以看到,原来数的所有二进制位都向左移动 1 位。原来位于左边的最高位 0 被移出舍弃,再向尾部追加 0 补位。最终到的结果是 22,相当于原来数的 2 倍。
右位移运算符
右位移运算符为»
,其运算规则是:按二进制形式把所有的数字向右移动对应的位数,低位移出(舍弃),高位的空位补零。
下面以11右移1位为例。
从图中可以看到,原来数的所有二进制位都向右移动 1 位。原来位于右边的最低位 1 被移出舍弃,再向最高位追加 0 补位。最终到的结果是 5,相当于原数整除 2 的结果。
无符号位移运算
无符号位移运算只有右移。无符号右移符号为>>>
。运算规则为:左操作数的值按右操作数指定的位数右移,移动得到的空位以零补充。简单的总结一下就是:忽略了符号位扩展,0补最高位 无符号右移运算符>>>
只是对32位和64位的值有意义
对于无符号右移,主要体现在负数上。对于编程语言来说,负数以补码的形式进行存储,而忽略符号位进行操作可能会改变数值的符号。
简单举个例子
-4 11111111111111111111111111111100
负数在java中以补码形式存储,-4的补码表示是11111111111111111111111111111100
2147483646 1111111111111111111111111111110
无符号右移1位,-4的补码表示的符号位也右移了1位,导致符号位变成0,成为正数 1073741822 111111111111111111111111111110
可以看到,无符号右移得到的结果与之前的变动可能会天差地别。