位(bitwise)运算就是按照数据转成二进制的表示形式进行计算,其执行效率非常高。按照运算的特点可以分为逻辑运算与移位运算。
Java中一共有 &、|、^、 ~、 <<、 >>、>>> 七个位运算符,除了 ~ ,其他6个运算符也可以与赋值运算符一起构成复合赋值运算符。
19.1 位运算符分类
位运算符可以分为逻辑运算符与移位运算符。
用于逻辑运算的位运算符有4个:&、|、^、 ~,它们的操作数是整型数值类型和字符类型,若对byte、short和char进行逻辑运算,它们会自动转换成int。除了 ~ ,其余三个操作数的操作数还可以是布尔类型。
- &:与运算符,操作数可以是整数、字符或布尔类型
- |:或运算,操作数可以是整数、字符或布尔类型
- ^:异或运算符,只要是不同的值,结果就是1;相同的值结构就是 0
- ~:非运算符,一元运算符,按位取反
用于移位运算的运算符有3个:<<、 >>、>>>,它们的操作数是整型数值类型和字符类型,若对byte、short和char进行逻辑运算,它们会自动转换成int。
- <<:左移运算符,移位后在低位补0
- >>:有符号右移运算符,移位时若值为正,则在高位插入0;若值为负,则在高位插入1
- >>>:无符号右移运算符,无论正负,都在高位插入0
19.2 与运算符
与运算符(&)支持的操作数:
- 整数:只有两个位上都是1,结果才是1
- 字符:转换为对应的ASCII码,然后按照整数运算规则进行运算
- 布尔:结果与&&类似,只要参与运算的都是true,其运算结果才是true;否则运算结果是false。但是需要注意的是, &不支持短路的特点。
下面以 & 为例介绍位运算的计算规则,比如:
int num1 = 4 & 5;
表达式 4 & 5 的计算规则如下:
将 4 转换为 2 进制的表示:00000000 00000000 00000000 00000100
将 5 转换为 2 进制的表示:00000000 00000000 00000000 00000101
然后对应位置的二进制数(0和1)进行计算,只有两个数都是1,结果才是1,否则就是0。
为了方便阅读,我将 int 类型的二进制表示按照每 8 位空一格,一共是32位。下面的两个二进制数最后一位分别是 0 和 1,结果对应位置上即为 0,倒数第3位对应位置都是 1,结果对应位置结果即为 1,其余对应位置上都是 0,结果就是 0。
00000000 00000000 00000000 00000100
00000000 00000000 00000000 00000101
------------------------------------
00000000 00000000 00000000 00000100
所以最终的结果是:00000000 00000000 00000000 00000100,然后输出时转换为10进制的形式,即为4。
如果是负数,二进制表示稍有不同,涉及到补码的概念,比如 -2 & -4 的计算如下:
11111111 11111111 11111111 11111110
11111111 11111111 11111111 11111100
------------------------------------
11111111 11111111 11111111 11111100
最终的结果是:11111111 11111111 11111111 11111100,然后输出时转换为10进制的形式,即为 -4。
19.3 或运算符
或运算符(|)和与运算符支持的操作数类型是一样的:
- 整数:只要两个位上有一个是1,结果就是1
- 字符:转换为对应的ASCII码,然后按照整数运算规则进行运算
- 布尔:结果与||类似,只有参与运算的操作数有一个是true,其运算结果就是true;否则运算结果是false。但是需要注意的是, | 不支持短路的特点。
下面举一个例子:
int num1 = 4 | 5;
同样的,先将 4 和 5 转成 2 进制形式,然后按照其运算规则计算,结果再以10进制输出。
00000000 00000000 00000000 00000100
00000000 00000000 00000000 00000101
------------------------------------
00000000 00000000 00000000 00000101
经过计算结果是:00000000 00000000 00000000 00000101,转成10进制为 5.
19.4 异或运算符
异或运算符(^)和与运算符支持的操作数类型是一样的:
- 整数:只要是不同的值,结果就是1;相同的值结构就是 0
- 字符:转换为对应的ASCII码,然后按照整数运算规则进行运算
- 布尔:参与运算的操作数(都是true或都是false)相同,结果是false,不相同结果就是true。
示例:
System.out.println(4 ^ 5);
计算过程如下:
00000000 00000000 00000000 00000100
00000000 00000000 00000000 00000101
------------------------------------
00000000 00000000 00000000 00000001
最后结果是:00000000 00000000 00000000 00000001,即为 1。
如果是布尔类型数据进行异或运算:
System.out.println(true ^ true); // false
System.out.println(true ^ false); // true
System.out.println(false ^ true); // true
System.out.println(false ^ false); // false
19.5 非运算符
非运算符(~)支持的操作数:
- 整数:转换为二进制表示后,按位进行取反操作,即 1 变 0 ,0 变 1
- 字符:转换为对应的ASCII码,然后按照整数运算规则进行运算
比如:
System.out.println(~4);
计算过程如下:
00000000 00000000 00000000 00000100
------------------------------------
11111111 11111111 11111111 11111011
最后结果是:11111111 11111111 11111111 11111011,即为 -5。
19.6 左移运算符
左移运算符(<<)支持的操作数:
- 整数:左移运算,在低位补0
- 字符:转换为对应的ASCII码,然后按照整数运算规则进行运算
示例:
System.out.println(4 << 2);
计算过程如下:
00000000 00000000 00000000 00000100
------------------------------------
00000000 00000000 00000000 00010000
将 4 的二进制表示向左移动 2 位,那么最高2位(最左边的 00)就没有了,最低的2位直接补上两个0。
所以最后结果是:00000000 00000000 00000000 00010000,即为 16。
可以看到,想将一个数翻1倍,就左移1次。
19.7 有符号右移运算符
有符号右移运算符(>>)支持的操作数:
- 整数:移位时若值为正,则在高位插入0;若值为负,则在高位插入1
- 字符:转换为对应的ASCII码,然后按照整数运算规则进行运算
示例:
System.out.println(4 >> 2);
计算过程如下:
00000000 00000000 00000000 00000100
------------------------------------
00000000 00000000 00000000 00000001
将 4 的二进制表示向右移动 2 位,那么最低2位(最右边的 00)就没有了,因为是正数,最高的2位直接补上两个0。
所以最后结果是:00000000 00000000 00000000 00000001,即为 1。
如果是负数,如:
System.out.println(-5 >> 2);
计算过程如下:
11111111 11111111 11111111 11111011
------------------------------------
11111111 11111111 11111111 11111110
将 -5 的二进制表示向右移动 2 位,那么最低2位(最右边的 11)就没有了,因为是负数,最高的2位直接补上两个1。
所以最后结果是:11111111 11111111 11111111 11111110,即为 -2。
可以看到要想将一个数减半,就进行有符号右移1位即可。
19.8 无符号右移运算符
有符号右移运算符(>>>)支持的操作数:
- 整数:移位时无论值的正负,都在高位插入0
- 字符:转换为对应的ASCII码,然后按照整数运算规则进行运算
示例1:
System.out.println(4 >>> 2);
计算过程如下:
00000000 00000000 00000000 00000100
------------------------------------
00000000 00000000 00000000 00000001
将 4 的二进制表示向右移动 2 位,那么最低2位(最右边的 00)就没有了,最高的2位直接补上两个0。
所以最后结果是:00000000 00000000 00000000 00000001,即为 1。
示例2:
System.out.println(-5 >>> 2);
计算过程如下:
11111111 11111111 11111111 11111011
------------------------------------
00111111 11111111 11111111 11111110
将 -5 的二进制表示向右移动 2 位,那么最低2位(最右边的 00)就没有了,最高的2位直接补上两个0。
所以最后结果是:00111111 11111111 11111111 11111110,即为 1073741822。
19.9 小结
Java位运算分为逻辑运算(&、|、、~)和移位运算(<<、>>、>>>)。逻辑运算对二进制位进行操作,移位运算通过移动二进制位实现数值变化。与运算符(&)对应位全1为1;或运算符(|)任意位为1则1;异或运算符()不同为1;非运算符(~)取反。移位运算包括左移(低位补0)、有符号右移(正补0负补1)和无符号右移(全补0)。位运算效率高,适用于整数和字符类型,部分运算符也可用于布尔运算(不短路)。

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



