移位运算
在计算机中,整数总是以二进制的形式表示。例如,int
类型的整数7
使用4字节表示的二进制如下:
00000000 0000000 0000000 00000111
可以对整数进行移位运算。对整数7
左移1位将得到整数14
,左移两位将得到整数28
:
int n = 7; // 00000000 00000000 00000000 00000111 = 7
int a = n << 1; // 00000000 00000000 00000000 00001110 = 14
int b = n << 2; // 00000000 00000000 00000000 00011100 = 28
int c = n << 28; // 01110000 00000000 00000000 00000000 = 1879048192
int d = n << 29; // 11100000 00000000 00000000 00000000 = -536870912
左移29位时,由于最高位变成1
,因此结果变成了负数。
类似的,对整数28进行右移,结果如下:
int n = 7; // 00000000 00000000 00000000 00000111 = 7
int a = n >> 1; // 00000000 00000000 00000000 00000011 = 3
int b = n >> 2; // 00000000 00000000 00000000 00000001 = 1
int c = n >> 3; // 00000000 00000000 00000000 00000000 = 0
如果对一个负数进行右移,最高位的1
不动,结果仍然是一个负数:
int n = -536870912;
int a = n >> 1; // 11110000 00000000 00000000 00000000 = -268435456
int b = n >> 2; // 11111000 00000000 00000000 00000000 = -134217728
int c = n >> 28; // 11111111 11111111 11111111 11111110 = -2
int d = n >> 29; // 11111111 11111111 11111111 11111111 = -1
还有一种无符号的右移运算,使用>>>
,它的特点是不管符号位,右移后高位总是补0
,因此,对一个负数进行>>>
右移,它会变成正数,原因是最高位的1
变成了0
:
int n = -536870912;
int a = n >>> 1; // 01110000 00000000 00000000 00000000 = 1879048192
int b = n >>> 2; // 00111000 00000000 00000000 00000000 = 939524096
int c = n >>> 29; // 00000000 00000000 00000000 00000111 = 7
int d = n >>> 31; // 00000000 00000000 00000000 00000001 = 1
对byte
和short
类型进行移位时,会首先转换为int
再进行位移。
仔细观察可发现,左移实际上就是不断地×2,右移实际上就是不断地÷2。
位运算
位运算是按位进行与、或、非和异或的运算。
与运算的规则是,必须两个数同时为1
,结果才为1
:
n = 0 & 0; // 0
n = 0 & 1; // 0
n = 1 & 0; // 0
n = 1 & 1; // 1
或运算的规则是,只要任意一个为1
,结果就为1
:
n = 0 | 0; // 0
n = 0 | 1; // 1
n = 1 | 0; // 1
n = 1 | 1; // 1
非运算的规则是,0
和1
互换:
n = ~0; // 1
n = ~1; // 0
异或运算的规则是,如果两个数不同,结果为1
,否则为0
:
n = 0 ^ 0; // 0
n = 0 ^ 1; // 1
n = 1 ^ 0; // 1
n = 1 ^ 1; // 0
对两个整数进行位运算,实际上就是按位对齐,然后依次对每一位进行运算。例如:
对两个整数进行位运算,实际上就是按位对齐,然后依次对每一位进行运算。例如:
// 位运算
public class Main {
public static void main(String[] args) {
int i = 167776589; // 00001010 00000000 00010001 01001101
int n = 167776512; // 00001010 00000000 00010001 00000000
System.out.println(i & n); // 167776512
}
}
上述按位与运算实际上可以看作两个整数表示的IP地址10.0.17.77
和10.0.17.0
,通过与运算,可以快速判断一个IP是否在给定的网段内。
运算优先级
在Java的计算表达式中,运算优先级从高到低依次是:
()
!
~
++
--
*
/
%
+
-
<<
>>
>>>
&
|
+=
-=
*=
/=
记不住也没关系,只需要加括号就可以保证运算的优先级正确。