按位运算
0.介绍
按位运算符 用于对基本数据类型中整型数据进行以单个位(bit) 为单位的运算。
Java中的位运算符包括:
| 运算符 | 中文名称 | 英文名称 |
|---|---|---|
| & | 按位与 | Bitwise AND |
| | | 按位或 | Bitwise OR |
| ~ | 按位非 | Bitwise NOT |
| ^ | 按位异或 | Bitwise XOR |
| << | 左移运算符 | Bitwise left shift |
| >> | 右移运算符 | Bitwise right shift |
| >>> | 无符号右移运算符 | Biswise unsigned right shift |
注意:下面的例子均假设整型数据为8位(即byte类型)
1.按位与&
规则
按位与运算符与逻辑与运算符的行为十分相似,按位与运算符比较两个操作数对应位的值,若均为1则返回1,否则返回0。如下表所示:
| A | B | 结果 |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
例如,对27和31这两个整型数作按位与运算:
- 将操作数表示为二进制形式,即:DEC 27 = BIN 00011011 , DEC 31 = BIN 00011111
- 按上表规则对操作数的对应位进行运算得到:BIN 00011011 = DEC 27
- 则表达式 27 & 31 的值为 27
应用
按位与运算符的一个应用就是判断一个整数是奇数还是偶数。这是因为当二进制数转化为十进制数时,最右位(rightmost digital,也称the least significant bit)表示十进制的20 = 1。若此位为0,那么该十进制数是若干2的次幂的和,为偶数(even);若此位为1,那么该十进制数是若干2的次幂的和加1,必为奇数(odd)。故只需使用表达式 num & 1 判断最右位的值即可。
Java代码片段如下:
public boolean isOdd(int num) {
if (num & 1 == 1)
return true;
else
return false;
}
与通过求余判断奇偶数的方法相比,此种方法性能较好。
2.按位或|
规则
类似的,按位或运算符与逻辑或运算符行为十分相似,按位或运算符比较两个操作数对应位的值,若均为0则返回0,否则返回1。如下表所示:
| A | B | 结果 |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 1 |
例如,对27和31这两个整型数作按位与运算:
- 将操作数表示为二进制形式,即:DEC 27 = BIN 00011011 , DEC 31 = BIN 00011111
- 按上表规则对操作数的对应位进行运算得到:BIN 00011111 = DEC 31
- 则表达式 27 | 31 的值为 31
应用
Android布局文件中有这样的写法,该写法将Button控件放置在Layout的水平居中,垂直下部的位置。
<Button
...
android:layout_gravity="bottom | center_horizontal"
...
/>
为了探究这样的写法的原理,考虑这样一个需求:
实现一个方法显示一个对话框,并在对话框上根据传入参数有选择地显示YES、NO和CANCEL三个按钮:
一种实现方法是(代码片段):
public class DialogWindow {
public static void showDialog(boolean btnYes, boolean btnNO, boolean btnCancel) {
if (btnYes) {
...
}
if (btnNo) {
...
}
if (btnCancel) {
...
}
}
}
但是上面代码的缺点是每次调用时都必须传入三个参数,并且需要保证参数的顺序正确。但如果在方法实现中使用按位运算,会使调用更加方便:
public class DialogWindow {
public static final int BTN_YES = 1;
public static final int BTN_NO = 2;
public static final int BTN_CANCEL = 4;
public static void showDialog(int option) {
if (option & BTN_YES != 0) {
...
}
if (option & BTN_NO != 0) {
...
}
if (option & BTN_CANCEL != 0) {
...
}
}
}
这时,如果想显示一个带有YES和CANCEL按钮的对话框,可以这样调用:
DialogWindow.showDialog(DialogWindow.BTN_YES | DialogWindow.BTN_CANCEL);
注意这里的参数均是2的次幂,DialogWindow.BTN_YES | DialogWindow.BTN_CANCEL = 0b00000001 | 0b00000100 = 0b00000101 。举例来说,当option与BTN_YES作按位与运算时,除了最右位为1,其余位均为0,结果非0,显示YES按钮;当option与BTN_NO作按位与运算时,所有位均为0,结果为0,不显示NO按钮。
3.按位非(按位取反)~
规则
与按位与和按位或不同的是,按位非是一个单目运算符,其行为类似于逻辑非运算符,当位的值为1时返回0,位的值为0是返回1。如下表所示:
| A | 结果 |
|---|---|
| 0 | 1 |
| 1 | 0 |
例如,对27这个整型数作按位非运算:
- 将操作数表示为二进制形式,即: DEC 27 = BIN 00011011
- 按上表规则将操作数的对应位进行运算得到:BIN 11100100
- 若该数为一个无符号整型数(即最高位不表示符号),则表达式**~27** 的值为 228
4.按位异或^
规则
按位异或运算符与逻辑运算符中的异或运算符行为类似。其运算规则是,比较两个操作数的对应位,如果相同则返回0,不同则返回1。如下表所示:
| A | B | 结果 |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
例如,对27和31这两个整型数作按位与运算:
- 将操作数表示为二进制形式,即:DEC 27 = BIN 00011011 , DEC 31 = BIN 00011111
- 按上表规则对操作数的对应位进行运算得到:BIN 00000100 = DEC 4
- 则表达式 27 ^ 31 的值为 4
应用
首先,按位异或运算符有一些特点:
- 0 ^ 0 = 0,1 ^ 0 = 1,即0异或任何数还是原数
- 0 ^ 1 = 1,1 ^ 1 = 0,即1异或任何数相当于把原数取反
- 任何数异或自己,相当于将自己置0
根据以上特点,按位异或运算有以下应用:
-
将特定位翻转:
例如,将二进制数BIN 00011011 的第三位和第六位翻转,可用BIN 00100100 与原数作异或运算,结果为BIN 00111111 -
交换两个数的值:
// 假如开始a = 0b00011011,b = 0b00011111
a = a ^ b; // a = 0b00000100
b = b ^ a; // b = 0b00011011
a = a ^ b; // a = 0b00011111
5.左移运算符<<
规则
左移运算符将操作数对应的二进制码整体左移指定位数,并将右边空出来的位用0补充(左移运算符的左边为操作数,右边为移动位数)。如下图所示:

表达式27 << 2 的值为108 。
从上面的例子也可以看出,在不丢失有效位的情况下,将一个操作数左移n位相当于将操作数乘以2n,如27 << 2 = 27 * 22 = 108 。一般来说,使用左移运算比直接使用乘法性能好。
6.右移运算符>>
规则
右移运算符将操作数对应的二进制码整体右移指定位数。若操作数为正数,即最高位为0,则将左边空出来的位用0补充;若操作数为负数,即最高位为1,则将左边空出来的位用1补充(右移运算符的左边为操作数,右边为移动位数)。
下图显示了对正数进行右移操作的过程:

表达式27 << 2 的值为6
下图显示了对负数进行右移操作的过程(Java中对负数的按位运算都是在对其补码操作):
-27 的补码为0b11100101

表达式 -27 << 2 的值为 -7
与左移运算符类似的是,在不损失有效位的情况下,将一个操作数右移n位相当于将操作数除以2n,如24 << 2 = 24 / 22 = 6,-24 << 2 = -24 / 22 = -6 ,但在计算27 << 2 时损失了有效位,故结果不等于27除以4。一般来说,使用右移运算比直接使用除法性能好。
应用
右移运算符和按位与运算符配合使用可以取出操作数中的指定位或连续几位,例如要取出二进制数a = 0b00011011的第四五位,可以使用如下表达式:
System.out.println((a & 0b00011000) >> 3);
7.无符号右移运算符>>>
规则
无符号右移运算符的行为与右移运算符的行为十分相似,区别在于,无论正数还是负数,该运算符均在左边空位中补0。

表达式 -27 >>> 2 的值为 57
注意:表达式-27 >>> 2的类型实际上是int类型,但这里仍假设数据的长度是8位。
本文介绍了Java中的位运算,包括按位与&、按位或|、按位非~、按位异或^、左移运算符<<、右移运算符>>以及无符号右移运算符>>>。通过位运算可以实现奇偶数判断、数值转换、数据位操作等功能,提高代码效率。
1661

被折叠的 条评论
为什么被折叠?



