在讲位运算符之前,我们先来回顾下本科时学过的一些计算机基础知识。
所谓原码就是二进制定点表示法,即最高位为符号位,正数为0,负数为1,其余位表示数值的大小。
反码:正数的反码与其原码相同,负数的反码是其原码逐位求反(符号位除外)。
补码:正数的补码与其原码相同,负数的补码为其反码加1。
整数在内存中是以补码的形式存储的。
一个简单的例子:
5的原码、补码、反码为
$$
原码:0000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0101 \\
反码:0000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0101 \\
补码:0000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0101
$$
-4的原码、补码、反码为:
$$
原码:1000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0100 \\
反码:1111 \ 1111 \quad 1111 \ 1111 \quad 1111 \ 1111 \quad 1111 \ 1011 \\
补码:1111 \ 1111 \quad 1111 \ 1111 \quad 1111 \ 1111 \quad 1111 \ 1100
$$
反过来,已知补码如何求原码呢?
已知补码如下,求其十进制表示?
$$
1111 \ 1111 \quad 1111 \ 1111 \quad 1111 \ 1111 \quad 1111 \ 1000
$$
先通过补码求得反码,即补码减去1
$$
\ 1111 \ 1111 \quad 1111 \ 1111 \quad 1111 \ 1111 \quad 1111 \ 1000 \\
\underline{- 0000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0001} \\
= 1111 \ 1111 \quad 1111 \ 1111 \quad 1111 \ 1111 \quad 1111 \ 0111
$$
除最高位(符号位)外,其他位按位求反,就得到了原码
$$
(1000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 1000)_2 = -8
$$
有了上面这些知识,位运算就很容易理解了。
按位与&
按位与运算的运算符是“&”,是双目运算符。如果两个操作数对应位都是1,则结果位为1,否则为0。
示例:5 & -4 = 4
$$
5的补码\\
\overbrace {0000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0101} \\
\& \\
\underbrace{1111 \ 1111 \quad 1111 \ 1111 \quad 1111 \ 1111 \quad 1111 \ 1100 } \\
-4的补码 \\
\Downarrow \\
\underbrace{0000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0100} \\
5\&-4的结果为十进制整数4
$$
按位或|
按位或运算的运算符是“|”,是双目运算符。如果两个操作数对应位都是0,则结果才是0,否则为1。
示例:3 | 6 = 7
$$
3的补码 \\
\overbrace {0000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0011} \\
| \\
\underbrace{0000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0110} \\
6的补码 \\
\Downarrow \\
\underbrace{0000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0111} \\
3 | 6的结果为十进制整数7
$$
按位非~
按位非运算,也称“按位取反”运算,运算符为“~”,是单目运算符。
运算法则:将操作数二进制中的1全部修改为0,0全部改为1
示例:~7 = -8
$$
7的补码\\
\overbrace {0000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0111} \\
\Downarrow \\
\underbrace{1111 \ 1111 \quad 1111 \ 1111 \quad 1111 \ 1111 \quad 1111 \ 1000} \\
\sim7的结果为十进制整数-8
$$
按位异或^
按位异或运算的运算符是“^”,是双目运算符。
运算法则:当两个操作数的二进制表示相同(同为0或同为1)时,结果为0,否则为1。
示例:7^3 = 4
$$
7的补码 \\
\overbrace{0000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0111} \\
\wedge \\
\underbrace{0000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0011} \\
3的补码 \\
\Downarrow \\
\underbrace{0000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0000 \quad 0000 \ 0100} \\
7^{\wedge} 3的结果为十进制整数4
$$
移位运算符
Java语言中的移位运算符有3种,其操作的数据类型只有byte、short、char、int和long5种类型。
- 左移运算符<<。左移空出的位置补0。
如12<<1 = 24:
$$
\quad \quad \quad \underline{0 \quad 0 \quad 0 \quad 0 \quad 1 \quad 1 \quad 0 \quad 0 }\\
\quad 抛弃 \rightarrow 0 \quad \underline{0 \quad 0\quad 0\quad 1 \quad 1\quad 0\quad 0} \quad 0 \leftarrow 补零 \\
结果为 2^{4}+2^{3} = 24
$$
- 右移运算符>>。如果最高位为0,则右移空出的位置补0;如果最高位为1,空出的位置补1。
如12>>1 = 6:
$$
\underline{0 \quad 0\quad 0\quad 0\quad 1\quad 1\quad 0 \quad 0 }\\
\quad 补零\rightarrow 0 \quad \underline{0 \quad 0 \quad 0\quad 0\quad 1 \quad 1\quad 0} \quad 0 \leftarrow 抛弃\\
结果为 2^{2}+2^{1} = 6
$$
- 无符号右移运算符>>>。不管最高位是0还是1,右移空出的位置都补0。
简单来说,一个数左移n位,相当于这个数乘以2的n次方;右移n位,相当于除以2的n次方。