在计算机中所有数据都是以二进制的形式存储的,位运算直接对二进制数据进行运算操作,省略了进制间的转换。
理论上,位运算比加减运算的效率略高,比乘除运算效率高很多,不过在目前最新的java版本下,加减运算的效率能和位运算持平,而乘除运算的效率还是落后于位运算很多。
在java中,主要有以下7种位运算符:
&(与)
规则:相同位置的数值都为1,结果为1,否则结果为0。
举例:
1 & 2 = 0
= 0000 0000 0000 0000 0000 0000 0000 0001 & 0000 0000 0000 0000 0000 0000 0000 0010
= 0000 0000 0000 0000 0000 0000 0000 0000
|(或)
规则:相同位置的数值有一个为1,结果为1,否则结果为0。
举例:
1 | 2 = 3
= 0000 0000 0000 0000 0000 0000 0000 0001 & 0000 0000 0000 0000 0000 0000 0000 0010
= 0000 0000 0000 0000 0000 0000 0000 0011
^(异或)
规则:相同位置的数值不相同时,结果为1,相同时,结果为0。
举例:
1 ^ 2 = 3
= 0000 0000 0000 0000 0000 0000 0000 0001 ^ 0000 0000 0000 0000 0000 0000 0000 0010
= 0000 0000 0000 0000 0000 0000 0000 0011
~(非)
规则:每个位置的数值都变更为相反的数,比如1变更为0,0变更为1。
举例:
~1 = -2
= ~ 0000 0000 0000 0000 0000 0000 0000 0001
= 1111 1111 1111 1111 1111 1111 1111 1110(补码)
= 1111 1111 1111 1111 1111 1111 1111 1101(反码)
= 1000 0000 0000 0000 0000 0000 0000 0010(原码)
<<(左移)
规则:所有数值向左移动,高位丢弃,低位补0。
如果你的计算机是32位系统时,左移32位相当于没有移动。这是因为移动的位数其实是对32求余后的余数。
比如x << n,其实是将x向左移动n % 32位。
举例:
-1 << 2 = -4
= 1111 1111 1111 1111 1111 1111 1111 1111 << 2
= 1111 1111 1111 1111 1111 1111 1111 1100(补码)
= 1111 1111 1111 1111 1111 1111 1111 1011(反码)
= 1000 0000 0000 0000 0000 0000 0000 0100(原码)
1 << 2 = 4
= 0000 0000 0000 0000 0000 0000 0000 0001 << 2
= 0000 0000 0000 0000 0000 0000 0000 0100
>>(右移)
规则:所有数值向右移动,低位丢弃,高位补符号位。
和 << 一样,移动的位数是求余后的余数。
举例:
-1 >> 2 = -1
= 1111 1111 1111 1111 1111 1111 1111 1111 >> 2
= 1111 1111 1111 1111 1111 1111 1111 1111(补码)
= 1111 1111 1111 1111 1111 1111 1111 1110(反码)
= 1000 0000 0000 0000 0000 0000 0000 0001(原码)
5 >> 2 = 1
= 0000 0000 0000 0000 0000 0000 0000 0101 >> 2
= 0000 0000 0000 0000 0000 0000 0000 0001
>>>(无符号右移)
规则:所有数值向右移动,低位丢弃,高位补0。
和 << 一样,移动的位数是求余后的余数。
举例:
-1 >>> 2 = 1073741823
= 1111 1111 1111 1111 1111 1111 1111 1111 >>> 2
= 0011 1111 1111 1111 1111 1111 1111 1111
1 >>> 2 = 0
= 0000 0000 0000 0000 0000 0000 0000 0001 >>> 2
= 0000 0000 0000 0000 0000 0000 0000 0000