Java中的位操作符有:
&:按位与。
|:按位或。
~:按位非。
^:按位异或。
<<:左移位运算符。
>>:右移位运算符。
<<<:无符号右移运算符。
与或非异或比较简单。
//按位与( & )
System.out.println(5 & 7);//输出为5
System.out.println(5 & 3);// 结果为1
System.out.println(4 & 1);// 结果为0
// 按位或( | )
System.out.println(5 | 3);// 结果为7
// 按位异或( ^ )
System.out.println(5 ^ 3);//结果为6
// 按位非( ~ )
System.out.println(~5);// 结果为-6
左移位运算符(<<):
将十进制数字转换为二进制后,整段数字向左移动,高位溢出的需要截断,低位补0。
比如2<<2,即2左移两位
//5左移两位
// 0000 0000 0000 0000 0000 0000 0000 0101 然后左移2位后,低位补0://
// 0000 0000 0000 0000 0000 0000 0001 0100 换算成10进制为20
//相当于5* 2的2次方
System.out.println(5 << 2);
//5左移三位
// 0000 0000 0000 0000 0000 0000 0000 0101 然后左移3位后,低位补0://
// 0000 0000 0000 0000 0000 0000 0010 1000 换算成10进制为40
//相当于5* 2的3次方
System.out.println(5 << 3);
输出结果:
所以,一个数左移多少位相当于这个数乘以2的多少次方。
右移位运算符(>>):
将十进制数字转换为二进制后,整段数字向右移动,低位溢出的需要截断,高位补符号位的数字,正数符号位为0补0,负数符号位为1补1。
比如,-6>>2结果为-2
//40右移两位
//0000 0000 0000 0000 0000 0000 0010 1000 初始值右移2位后,高位补符号位的0得:
//0000 0000 0000 0000 0000 0000 0000 1010 换算成10进制为10
//相当于5/ 2的2次方
System.out.println(40 >> 2);
//-40转换成二进制,首先需要写出对应正数40的二进制,然后将符号位置为1,符号位不变,各位取反,再加1,就得到了对应的负数的二进制
// 0000 0000 0000 0000 0000 0000 0010 1000 40的二进制
// 1000 0000 0000 0000 0000 0000 0010 1000 将符号位置为1
// 1111 1111 1111 1111 1111 1111 1101 0111 除符号位外按位取反
// 1111 1111 1111 1111 1111 1111 1101 1000 再加1,得-40的二进制
//-40右移两位
// 1111 1111 1111 1111 1111 1111 1101 1000 初始值右移2位后,高位补符号位的1得:
// 1111 1111 1111 1111 1111 1111 1111 0110 转换为十进制是先减一再按位取反,不看符号位就是其对应的正数,换算成十进制为-10
System.out.println(-40 >> 2);
输出结果:
所以,一个数右移多少位相当于这个数除以2的多少次方。
无符号右移(>>>)
将十进制数字转换为二进制后,整段数字向右移动,低位溢出的需要截断,高位补0(不管符号位是什么)
所以说,不管是负数还是正数,无符号右移之后符号位都会变为0,也就是都会变为正数。
无符号右移对于正数来说和不同右移运算符一样。
比如,-1>>>1结果为2147483647,也就是得到了Integer.MAX_VALUE
//1111 1111 1111 1111 1111 1111 1111 1111 -1的二进制,然后右移一位,高位补0
//0111 1111 1111 1111 1111 1111 1111 1111 转换为十进制为2147483647,也就是Integer.MAX_VALUE
System.out.println(-1 >>> 1);
//和普通右移运算符一样,得到10
System.out.println(40 >>> 2);
输出结果:
两个法则:
法则一:任何数左移(右移)32的倍数位等于该数本身。
法则二:在位移运算m<<n的计算中,若n为正数,则实际移动的位数为n%32,若n为负数,则实际移动的位数为(32+n%32),右移,同理。
常见使用场景:
1.求幂运算时,比如求m*2^n,可以直接写为 m<<n
System.out.println("3*2^3=" + (3<<3));//3*2^3=24
2.判断一个数的奇偶
n&1 == 1?”奇数”:”偶数”
奇数和偶数在二进制中的区别就是最后一位是0还是1,奇数是1,偶数是0。
因为1的二进制前面全是0,只有最后一位是1,那么这个n不管前面几位是什么,只要与0相与就一定是0,所以就保证了只看最后一位。偶数最后一位是0,与1相与就是0,奇数最后一位是1,与1相与就是1。这样就可以判断出来了。
3.不用临时变量交换两个数的值
public static int[] reverse(int[] nums){
int i = 0;
int j = nums.length-1;
while(j>i){
nums[i]= nums[i]^nums[j];
nums[j] = nums[j]^nums[i];
nums[i] = nums[i]^nums[j];
j--;
i++;
}
return nums;
}
原理: