运算符 结果
~ 按位非(NOT)(一元运算)
& 按位与(AND)
| 按位或(OR)
^ 按位异或(XOR)
>> 右移
>>> 右移,左边空出的位以0填充
续表
运算符 结果
<< 左移
&= 按位与赋值
|= 按位或赋值
^= 按位异或赋值
>>= 右移赋值
>>>= 右移赋值,左边空出的位以0填充
<<= 左移赋值
既然位运算符在整数范围内对位操作,因此理解这样的操作会对一个值产生什么效果是重要的。具体地说,知道Java是如何存储整数值并且如何表示负数的是有用的。因此,在继续讨论之前,让我们简短概述一下这两个话题。
所有的整数类型以二进制数字位的变化及其宽度来表示。例如,byte型值42的二进制代码是00101010,其中每个位置在此代表2的次方,在最右边的位以20开始。向左下一个位置将是21,或2,依次向左是22,或4,然后是8,16,32等等,依此类推。因此42在其位置1,3,5的值为1(从右边以0开始数);这样42是21+23+25的和,也即是2+8+32 。
所有的整数类型(除了char类型之外)都是有符号的整数。这意味着他们既能表示正数,又能表示负数。Java使用大家知道的2的补码(two's complement)这种编码来表示负数,也就是通过将与其对应的正数的二进制代码取反(即将1变成0,将0变成1),然后对其结果加1。例如,-42就是通过将42的二进制代码的各个位取反,即对00101010取反得到11010101,然后再加1,得到11010110,即-42 。要对一个负数解码,首先对其所有的位取反,然后加1。例如-42,或11010110取反后为00101001,或41,然后加1,这样就得到了42。
如果考虑到零的交叉(zero crossing)问题,你就容易理解Java(以及其他绝大多数语言)这样用2的补码的原因。假定byte类型的值零用00000000代表。它的补码是仅仅将它的每一位取反,即生成11111111,它代表负零。但问题是负零在整数数学中是无效的。为了解决负零的问题,在使用2的补码代表负数的值时,对其值加1。即负零11111111加1后为100000000。但这样使1位太靠左而不适合返回到byte类型的值,因此人们规定,-0和0的表示方法一样,-1的解码为11111111。尽管我们在这个例子使用了byte类型的值,但同样的基本的原则也适用于所有Java 的整数类型。
因为Java使用2的补码来存储负数,并且因为Java中的所有整数都是有符号的,这样应用位运算符可以容易地达到意想不到的结果。例如,不管你如何打算,Java用高位来代表负数。为避免这个讨厌的意外,请记住不管高位的顺序如何,它决定一个整数的符号。