Java位运算
快速备忘
| 符号 | 描述 | 运算规则 |
|---|---|---|
| & | 与 | 两个位都是1,结果才为1 |
| | | 或 | 两个位都是0,结果才为0 |
| 异或 | 相同为0,相异为1 | |
| ~ | 非 | 0变1,1变0 |
| << | 左移 | 符号位不变,数据位左移,高位丢,低位补0 |
| >> | 右移 | 符号位不变,数据往右移,低位丢,高位补充符号位 |
| >>> | 无符号右移 | 全部数据往右移动,溢出的低位丢弃,高位补充0。 |
数字运算规则
位运算的基础
计算机在运算时是以二进制进行数字运算,准确的说,是用补码的格式进行运算。以下简单介绍一下补码的规则,以Java语言的int类型为例。
int
int类型,占4个字节,每个字节等于8个二进制位,即用32个二进制表示一个int数据。下面以数字7和-17为例。
原码
最高位为符号位,0表示正数,1表示负数。直接将十进制转换为二进制。
7 : 0000 0000 0000 0000 0000 0000 0000 0111
-17: 1000 0000 0000 0000 0000 0000 0001 0001
反码
正数和原码相同。负数符号位不变,其他在==原码==基础上按位取反(1变0, 0变1)
-17: 1111 1111 1111 1111 1111 1111 1110 1001
补码
正数和原码相同。负数符号位不变,其他在==反码==基础上+1
-17: 1111 1111 1111 1111 1111 1111 1110 1010
逻辑运算(与/或/非/异或)
与、或
最常用的运算符&、|,注意与常用的&&、||是不同的,后者是短路与、或。
举例:(a == 1) | (b == 2)左右两边的表达式都会进行判断,而短路或判断前面的表达式为true,就不会判断右边的了。
非
或者叫取反,这里面唯一一个单目运算符。
异或
相异为1,相同为0。
位移运算
左移<<
符号位不变,数据往左移动,低位补0,溢出的高位丢弃。
a << n,a左移n位,相当于乘以 2^n^,注意左移太多位会溢出。
右移>>
符号位不变,数据往右移动,溢出的低位丢弃,高位补充符号位
a >> n,a右移n位,相当于乘以2^1/n^。注意结果不是整数的右移,如1 >> 10 = 0; 5 >> 1 = 2,这里就不详细解释了。
无符号右移>>>
数据往右移动,溢出的低位丢弃,高位补充0。
正数效果和右移一样,负数则不同。
小技巧
你可以不用,但是你得能看懂
奇偶性判断
n & 1 == 1 ? 奇数 :偶数
1的补码是0000 .... 0001,即最后一位是1,其余都为0
无论正负,奇数最后一位一定1,奇数最后一位前面的所有位 &1与之后都是0。所以可以根据最后一位是不是1来判断是不是奇数。
乘除
乘2的n次方,数a乘以2的n次方,a << n;
判断一个数是否是2的n次方, a & (a - 1) == 0;
交换两个整形数字
a = a ^ b;
b = a ^ b;
a = a ^ b;
但是要特别注意,如果写一个函数交换数组中的两个值,可能会下意识的这么写
void swap(int[] num, int i, int j){
num[i] = num[i] ^ num[j];
num[j] = num[i] ^ num[j];
num[i] = num[i] ^ num[j];
}
这样写是有问题的,因为当i == j时,会出现为0的情况。加个判断就好