所有的位运算都是在二进制下来进行运算的,再二进制下只有0/1。
1. ~ 位求反
运算符规则是:将运算符后二进制数反转,0变1,1变 0,所以对一个数取反偶数次结果是它本身。
例如:
0000 0000 0000 0000 0000 0000 0000 0011 -> 3
1111 1111 1111 1111 1111 1111 1111 1100 -> ~ 3 = -4
常用场景:
求相反数: ~a + 1
2. << 左移
运算符规则是:各二进位全部左移若干位,高位丢弃,低位补0。
例如:6 << 2 = 24
0000 0000 0000 0000 0000 0000 0000 0110 -> 6
0000 0000 0000 0000 0000 0000 0001 1000 -> 6 << 2 = 24
我们将6的二进位向左移动两位,低位补上两个0,高位丢弃,得出来的结果就是24。
常用场景:
左移常
被用来做 * (2 ^ n)的运算
,因为直接基于二进制运算,所以左移效率比 * (2 ^ n)高。
3.>> 右移
运算符规则是:各二进位全部右移若干位,正数高位补0,负数高位补1,低位丢弃。
例如: 12 >> 2 = 3
0000 0000 0000 0000 0000 0000 0000 1100 -> 12
0000 0000 0000 0000 0000 0000 0000 0011 -> 12 >> 2 = 3
因为12是正数,右移过程中高位补上两个0,低位丢弃,得出来的结果就是3。
例如:-12 >> 2 = -3
1111 1111 1111 1111 1111 1111 1111 0100 -> -12
1111 1111 1111 1111 1111 1111 1111 1101 -> -12 >> 2 = -3
因为-12是负数,右移过程中高位补上两个1,低位丢弃,得出来的结果就是-3。
常用场景:
右移常
被用来做 / (2 ^ n)的
运算,因为直接基于二进制运算,所以右移效率比 / (2 ^ n)高。
4. >>> 无符号右移
运算符规则是:各二进位全部右移若干位,高位补0,低位丢弃。
例如: 12 >>> 2 = 3
0000 0000 0000 0000 0000 0000 0000 1100 -> 12
0000 0000 0000 0000 0000 0000 0000 0011 -> 12 >>> 2 = 3
我们将12的二进位向右移动两位,高位补上两个0,低位丢弃,得出来的结果就是24。
例如:-12 >>> 2 = 1073741821
1111 1111 1111 1111 1111 1111 1111 0100 -> -12
0011 1111 1111 1111 1111 1111 1111 1101 -> -12 >> 2 = 1073741821
我们将-12的二进位向右移动两位,高位补上两个0,低位丢弃,得出来的结果就是1073741821。
5. & 位与
运算符规则是:运算符两边有0,结果就为0 ,只有当两边同时为1是,结果才为1。
如下:
0 & 0 = 0; 0 & 1 = 0; 1 & 0 = 0; 1 & 1= 1;
例如:3&5
0000 0000 0000 0000 0000 0000 0000 0011 -> 3
0000 0000 0000 0000 0000 0000 0000 0101 -> 5
0000 0000 0000 0000 0000 0000 0000 0001 -> 3 & 5 = 1
位与运算的特殊用途:
1.清零(将一个单元与0进行位与运算结果为零)
2.取一个数指定位(例如取num=1010 1101的低四位 则将num&0xF得到0000 1101)。
3.判断奇偶性:用if ((a & 1) == 0) 代替 if (a % 2 == 0)来判断a是不是偶数。
6. | 位或
运算规则就是 运算符两边有1,结果就为1 ,只有当两边同时为0是,结果才为0。
如下:
0 | 0 = 0; 0 | 1 = 1; 1 | 0 = 1; 1 | 1 = 1 ;
例如:3|5
0000 0000 0000 0000 0000 0000 0000 0011 -> 3
0000 0000 0000 0000 0000 0000 0000 0101 -> 5
0000 0000 0000 0000 0000 0000 0000 0111 -> 3 | 5 = 7
另,负数按补码形式参加按位或运算。
使用场景:
下面这个方法是摘自HashMap类,这个算法来修改用户使用构造器传进来的size的,这个算法是使用移位和或结合来实现的,性能上比循环判断要好。
public static final int tableSizeFor(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
7. ^ 位异或
运算规则是:当运算符两边相同位置都是相同,结果返回0,不相同时返回1。
例如:3 ^ 5 = 1
0000 0000 0000 0000 0000 0000 0000 0011 -> 3
0000 0000 0000 0000 0000 0000 0000 0101 -> 5
0000 0000 0000 0000 0000 0000 0000 0110 -> 3 ^ 5 = 6
通常我们交换两个数会使用一个临时变量来帮忙:
int t = a;
a = b;
b = t;
使用 ^ 位运算符==(装逼必备)==
a ^= b;
b ^= a;
a ^= b;
//冒泡排序的 交换数字耶
for(int i=0;i<k-2;i++) {
for(int j=i+1;j<k-1;j++) {
if(a[i] < a[j]) {
a[i] ^= a[j] ^= a[i] ^= a[j];
//交换数字
}
}
}