前言
最近在看hashMap的源码,看到了一些位运算符,决定深入研究学习一下位运算符。
位运算
定义:程序中的所有数在计算机内存中都是以二进制的形式储存的。位运算说穿了,就是直接对整数在内存中的二进制位进行操作。
位运算符
Java中的位运算符一共有:&、|、^ 、<<、>>、>>>、~这7种
1.&(与)、|(或)、^(异或)
public static void main(String[] args) { int a = 10; System.out.println("a的二进制表示:" + Integer.toBinaryString(a)); int b = 11; System.out.println("b的二进制表示:" + Integer.toBinaryString(b)); int i = a & b; System.out.println("a & b = " + i + ",i的二进制表示:" + Integer.toBinaryString(i)); i = a | b; System.out.println("a | b = " + i + ",i的二进制表示:" + Integer.toBinaryString(i)); i = a ^ b; System.out.println("a ^ b = " + i + ",i的二进制表示:" + Integer.toBinaryString(i)); }
运行结果
a的二进制表示:1010 b的二进制表示:1011 a & b = 10,i的二进制表示:1010 a | b = 11,i的二进制表示:1011 a ^ b = 1,i的二进制表示:1
可以通过Java中Integer类自带将int转为二进制表示的方法查看二进制
这里a ^ b 的二进制表示可以看成0001
可以看出
& (与):当a和b二进制表示上相同位数都为1时,i的对应位数上的值才为1(既11-->1 10 -->0 01-->0 00-->0),不难看出 i <= min(a,b)
| (或):当a和b二进制表示上相同位数都为0时,i的对应位数上的值才为0(既11-->1 10 -->1 01-->1 00-->0),不难看出 i >= max(a,b)
^(异或):当a和b二进制表示上相同位数相同时,i的对应位数上的纸值为0(既11-->0 10 -->1 01-->1 00-->0)
2. <<(左移)、>>(带符号右移)、>>>(无符号右移)
public static void main(String[] args) { int i = 1 << 2; System.out.println("1 << 2 = " + i); i = 1 << 30; System.out.println("1 << 30 = " + i); i = 1 << 31; System.out.println("1 << 31 = " + i); i = 1 >> 1; System.out.println("1 >> 1 = " + i); i = 1 >> 32; System.out.println("1 >> 32 = " + i); i = -1 >> 1; System.out.println("-1 >> 1 = " + i); i = -1 >>> 1; System.out.println("-1 >>> 1 = " + i); }
运行结果
1 << 2 = 4 1 << 30 = 1073741824 1 << 31 = -2147483648 1 >> 1 = 0 1 >> 32 = 1 -1 >> 1 = -1 -1 >>> 1 = 2147483647
一般情况下
a << n = (a * (2的n次方 ))
a >> n=(a-a%2)/(2的n次方)
但是,可以看到上面的例子中可以列出不少返例
这其中主要因为Java中int的范围
首先,Java中int的范围是 -2的32次~2的32次-1
另外,我们有没有考虑过i的边界问题,当i = 2的32次-1后,再+1,会出现什么后果?
public static void main(String[] args) {
int i = Integer.MAX_VALUE +1;
System.out.println(i);
System.out.println(Integer.toBinaryString(i));
}
运行结果
-2147483648(-2的32次方。int的最小值)
10000000000000000000000000000000
我们知道int的长度是32位的,要表示Int的正负,Java中的做法是在第32位上做标记,第32位=0时,int为正数,第32位=-1时,int为负数
所以
二进制:00000000000000000000000000000000 ,代表最小的正数0
二进制:10000000000000000000000000000000 ,代表最小的负数-2147483648
从二进制计算的角度不难理解,Integer.MAX_VALUE+1 = Integer.MIN_VALUE
这就是为什么 1<<31 = -2147483648
我们再来看
1 >> 1 = 0 和 1 >> 32 = 1
这里我理解为 二进制中移位运算实际是对一个长度为63的二进制数进行操作,其中连续的32位表示int的值,剩余部分全部为0。
然后再讲这整个63位的二进制数看成一个圆(循环队列)
所以,无论一个数左移或者右移32位,始终是这个数本身。
然后,我们来看一下 -1 >>1 = -1 和 -1>>>1 = 2147483647
先从字面上理解,>> 带符号右移,>>>无符号右移
再进一步解释就很容易了,63位长度的二进制数中,其中连续的32位表示int的值,剩余的31位再做>>操作时,保持与int的符号相同的值(即int位负,其余31位都为1,int为正,其余31位都为0)
而>>>无符号右移,则是无论int为何,其余31位全部为0
3.~(取反)
public static void main(String[] args) { int i = 10; System.out.println(Integer.toBinaryString(i)); System.out.println(Integer.toBinaryString(~i)); }
运行结果
1010 11111111111111111111111111110101
取反很容易理解,将0替换成1,将1替换成0
将10的二进制表示补充至完整的32位
00000000000000000000000000001010 取反则等于11111111111111111111111111110101
可以看出 i + ~i = -1
---------------------------------------------------------------------------------------------------------------------
第一次写博客,很多地方都是个人理解,如果写得不对的地方,请拨冗指正,谢谢!