3.7.3 位运算符
3.7.3 位运算符
Java
支持的位运算符有如下7个
运算符 | 描述 |
---|---|
& |
按位与。当两位同时为1时才返回1。 |
` | ` |
~ |
按位非,或者叫按位取反。单目运算符,将操作数的每个位(包括符号位)全部取反 |
^ |
按位异或。当两位相同时返回0,不同时返回1。 |
<< |
左移运算符 |
>> |
右移运算符 |
>>> |
无符号右移运算符 |
一般来说,位运算符只能操作整数类型的变量或值。
按位与 按位或 按位异或 的运算法则如表3.3所示。
第一个操作数 | 第二个操作数 | 按位与 | 按位或 | 按位异或 |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 0 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
按位非只需要一个操作数,这个运算符将把操作数在计算机底层的二进制码按位(包括符号位)取反。
程序示例 安慰与 按位或
如下代码测试了按位与和按位或运算的运行结果。
1 | System.out.println(5 & 9); // 将输出1 |
5的二进制码是000_0101(省略了前面的24个0),而9的二进制码是0000_1001(省略了前面的24个0)。运算过程如图3.12所示
程序示例 按位异或 按位取反
下面是按位异或和按位取反的执行代码
1 | System.out.println(~-5); // 将输出4 |
下面通过图3.13来介绍运算原理:
而5^9的运算过程如图3.14所示:
程序示例 左移运算
左移运算符是**将操作数的二进制码整体左移指定位数,左移后右边空出来的位以0填充**。例如如下代码
1 | System.out.println(5 << 2); // 输出20 |
下面以-5为例来介绍左移运算的运算过程,如图3.15所示。
在图3.15中,上面的32位数是5的补码,左移两位后得到一个二进制补码,这个二进制补码的最高位是1,表明是一个负数,换算成十进制数就是20。
右移运算符 无符号右移运算符
Java
的右移运算符有两个:>>和>>>。
右移运算符 以符号位填充
对于右移运算符>>
而言,把第一个操作数的二进制码右移指定位数后,左边空出来的位以原来的符号位填充,即
如果第一个操作数原来是正数,则左边补0;
如果第个操作数是负数,则左边补1。
无符号右移运算符 以0填充
>>>
是无符号右移运算符,它把第一个操作数的二进制码右移指定位数后,左边空出来的位总是以0填充
1 | System.out.println(-5 >> 2); // 输出-2 |
下面用示意图来说明>>
和>>>
运算符的运算过程
右移不改变正负符号
从图3.16来看,-5右移2位后左边空出2位,空出来的2位以符号位补充。从图中可以看出,右移运算后得到的结果的正负与第一个操作数的正负相同。右移后的结果依然是一个负数,这是一个二进制补码,换算成十进制数就是-2。
无符号右移总是得到正数
从图3.17来看,-5无符号右移2位后左边空出2位,空出来的2位以0补充。从图中可以看出,无符号右移运算后的结果总是得到一个正数。图3.17中下面的正数是1073741822(2^30-2)。
进行移位运算时还要遵循如下规则。
- 对于低于
int
类型(如byte
、short
和char
)的操作数总是先自动类型转换为int
类型后再移位 - 对于
int
类型的整数移位a>>b
,因为int
类型是32位,所以当b>32
时,所以系统先用b对32求余,得到的结果才是真正移位的位数。例如,a>>33
和a>>1
的结果完全一样,而a>>32
的结果和a本身相同。 - 对于
long
类型的整数移位a>>b
,因为long
类型是64位,所以当b>64
时,总是先用b对64求余,得到的结果才是真正移位的位数。
左移相当于乘以2的n次方 右移相当于除以2的n次方
当进行移位运算时,只要被移位的二进制码没有发生有效位的数字丢失,不难发现左移n位就相当于乘以2的n次方,右移n位则是除以2的n次方。不仅如此,进行移位运算不会改变操作数本身,只是得到了一个新的运算结果,而原来的操作数本身是不会改变的