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次方。不仅如此,进行移位运算不会改变操作数本身,只是得到了一个新的运算结果,而原来的操作数本身是不会改变的