既然都有了原码,反码,补码的概念,那位运算也就呼之欲出了。
何为位运算,就是对二进制的0和1进行操作,在代码中可以进行高低位的截取,哈希计算,甚至用在乘除法算法中。
位运算的几个操作符号:<<(左移),>>(右移),&(与),|(或),^(异或)。
<<操作符:二进制左移
举例:1<<1底层实际是:0000 0001左移1位变0000 0010即2
>>操作符:二进制右移
举例:2>>1底层实际是:0000 0010右移1位变0000 0001即1
&操作符:二进制位上只有都为1才是1
举例:2&1底层实际是:0000 0010 & 0000 0001变0000 0000即0
举例:3&1底层实际是:0000 0011 & 0000 0001变0000 0001即1
|操作符:二进制位上只要有1个为1即1
举例:2|1底层实际是:0000 0010 | 0000 0001变0000 0011即3
^操作符:二进制位只有当不同时才为1,即0和1为1,1和1为0
举例:2^1底层实际是:0000 0010 ^ 0000 0001变0000 0011即3
可以得出一个结论:向右移动1位的时候近似表示除以2
但是需要注意的是并不是一定,举个例子:
十进制的技术转换为二进制后,向右移动的时候,最右边的1将直接抹去,说明向右移对于奇数并非完全相当于除以2.
注意注意!
很重要的一点就是位运算操作是针对补码进行的,如果是正数,补码还是原码不影响,关键是负数,对负数进行位操作时,一定要先转换为补码才行。
具体的原码补码可以参考这篇:
原码,反码,补码的简单理解
还有个结论:在左移<<和右移>>两种运算中,符号位均参与移动,除负数往右边移动,高位补1之外,其他情况均在空位处补0(来自码出高效)
注意:
负数的位运算要先转换为补码,如果最后的结果的最高位为1还需要进行补码操作
参考:
https://blog.csdn.net/u013790019/article/details/44627719
位运算的其他运用:用来代替&&和||。
这个时候你就会问了 &和&&还有|和||不是一个作用吗,的确这两者的运算都可以作用于条件表达式,但是后者&&和||会发生短路现象,举例:
boolean a = true;
boolean b = true;
boolean c = (a=(1==2)) && (b=(1==2));
结果是:
true
结果分析:
因为&&前边的表达式(1==2)结果为false,触发短路,直接退出,最后a的值为false ,b的值为true。如果吧&&换成按位与&,则执行的结果为a与b都是false
同理||和|一样。
但是注意:
逻辑与&和逻辑或|只能对布尔类型的条件表达式进行运算,像7&8这种运算表达式是错误的。
再来刷两道位运算的题目更加了解下:
异或操作符题目:
136. 只出现一次的数字
题解:
class Solution {
public int singleNumber(int[] nums) {
int temp=0;
for(int i=0;i<nums.length;i++){
temp^=nums[i];
}
return temp;
}
}
综合题目:
137. 只出现一次的数字 II
题解:
https://blog.csdn.net/w8253497062015/article/details/80058180