Java学习之旅第一季-19:运算符之位运算符

位(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)。位运算效率高,适用于整数和字符类型,部分运算符也可用于布尔运算(不短路)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值