Java 位运算符

BitTigerio 2018-03-03

前言

最近在看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

---------------------------------------------------------------------------------------------------------------------

第一次写博客,很多地方都是个人理解,如果写得不对的地方,请拨冗指正,谢谢!

相关推荐