java拾遗:通过示例理解位运算

2015-01-29

环境:jdk 1.7。

Java的位运算(Bitwise operation)直接对整数类型的位进行操作,这些整数类型包括long、int、short、char和 byte。

在java中:
byte -> 8 bits
short -> 16 bits
int -> 32 bits
long -> 64 bits
char -> 16 bit

int的位运算


基础

在java中,int数据底层以补码形式存储。关于原码、反码、补码,《原码, 反码, 补码 详解》给出了很精彩的解释。

int型变量使用32bit存储数据,其中最高位是符号位,0表示正数,1表示负数。例如:

// 若最高的几位为0则不输出这几位,从为1的那一位开始输出
System.out.println(Integer.toBinaryString(10)); 
System.out.println(Integer.toBinaryString(-10));

会输出(手工排版过,以下的输出均会被手工排版):

                            1010
11111111111111111111111111110110

加法运算1:

System.out.println(Integer.toBinaryString(11));
System.out.println(Integer.toBinaryString(10));
System.out.println(Integer.toBinaryString(21));

输出:

 1011
 1010
10101

加法运算2:

System.out.println(Integer.toBinaryString(-11));
System.out.println(Integer.toBinaryString(-10));
System.out.println(Integer.toBinaryString(-21));

输出:

11111111111111111111111111110101
11111111111111111111111111110110
11111111111111111111111111101011

加法运算3:

System.out.println(Integer.toBinaryString(11));
System.out.println(Integer.toBinaryString(-10));
System.out.println(Integer.toBinaryString(1));

输出:

                            1011
11111111111111111111111111110110
                               1

加法运算4:

System.out.println(Integer.toBinaryString(-11));
System.out.println(Integer.toBinaryString(10));
System.out.println(Integer.toBinaryString(-1));

输出:

11111111111111111111111111110101
                            1010
11111111111111111111111111111111

对于2进制补码的加法运算,和平常的计算一样,而且符号位也参与运算,不过最后只保留32位。

左移<<

System.out.println(Integer.toBinaryString(11));
System.out.println(Integer.toBinaryString(11<<2));  // 左移2位,44
System.out.println(Integer.toBinaryString(11<<28)); // -1342177280,负数
System.out.println(Integer.toBinaryString(-11));
System.out.println(Integer.toBinaryString(-11<<2)); // -44

输出:

                            1011
                          101100
10110000000000000000000000000000
11111111111111111111111111110101
11111111111111111111111111010100

可以看出符号位也参与移位,移位时右侧空出的位补0。

右移>>

System.out.println(Integer.toBinaryString(11));
System.out.println(Integer.toBinaryString(11>>2));   // 2
System.out.println(Integer.toBinaryString(-11));
System.out.println(Integer.toBinaryString(-11>>2));  // -3

输出:

                            1011
                              10
11111111111111111111111111110101
11111111111111111111111111111101

对于右移,符号位参与移位。对于正数而言空出的位置补0,负数则补1。

无符号右移 >>>

System.out.println(Integer.toBinaryString(11));
System.out.println(Integer.toBinaryString(11>>>2));  // 2
System.out.println(Integer.toBinaryString(-11));
System.out.println(Integer.toBinaryString(-11>>>2)); // 1073741821

输出:

                            1011
                              10
11111111111111111111111111110101
  111111111111111111111111111101

对于无符号右移,符号位参与移位。对于正数和负数,空出的位置均补0。

与运算

System.out.println(Integer.toBinaryString(11));
System.out.println(Integer.toBinaryString(10)); 
System.out.println(Integer.toBinaryString(11 & 10)); 
System.out.println(Integer.toBinaryString(-11));
System.out.println(Integer.toBinaryString(10)); 
System.out.println(Integer.toBinaryString(-11 & 10));

输出:

                            1011
                            1010
                            1010
11111111111111111111111111110101
                            1010
                               0

或运算

System.out.println(Integer.toBinaryString(11));
System.out.println(Integer.toBinaryString(10)); 
System.out.println(Integer.toBinaryString(11 | 10)); 
System.out.println(Integer.toBinaryString(-11));
System.out.println(Integer.toBinaryString(10)); 
System.out.println(Integer.toBinaryString(-11 | 10));

输出:

                            1011
                            1010
                            1011
11111111111111111111111111110101
                            1010
11111111111111111111111111111111

异或运算

System.out.println(Integer.toBinaryString(11));
System.out.println(Integer.toBinaryString(10)); 
System.out.println(Integer.toBinaryString(11 ^ 10)); 
System.out.println(Integer.toBinaryString(-11));
System.out.println(Integer.toBinaryString(10)); 
System.out.println(Integer.toBinaryString(-11 ^ 10));

输出:

                            1011
                            1010
                               1
11111111111111111111111111110101
                            1010
11111111111111111111111111111111

非运算

System.out.println(Integer.toBinaryString(11));
System.out.println(Integer.toBinaryString(~11)); 
System.out.println(Integer.toBinaryString(-11)); 
System.out.println(Integer.toBinaryString(~-11));

输出:

                            1011
11111111111111111111111111110100
11111111111111111111111111110101
                            1010

long的位运算


和int类似,就是位数变成了64bit。举个例子:

System.out.println(Long.toBinaryString(-10L));
System.out.println(Long.toBinaryString(-10L<<2));

输出:

1111111111111111111111111111111111111111111111111111111111110110
1111111111111111111111111111111111111111111111111111111111011000

byte、short、char的位运算


先被拓宽为int类型,然后进行位运算。类ShortCharacterByte中也没有toBinaryString方法。例如:

short i;
byte b;
i = 5;
System.out.println(Integer.toBinaryString(i));
System.out.println(Integer.toBinaryString(i<<2));
i = -5;
System.out.println(Integer.toBinaryString(i));
System.out.println(Integer.toBinaryString(i<<2));
b = -128;
System.out.println(Integer.toBinaryString(b));
System.out.println(Integer.toBinaryString(b<<2));

输出:

                             101
                           10100
11111111111111111111111111111011
11111111111111111111111111101100
11111111111111111111111110000000
11111111111111111111111000000000

不止这些


对于移位运算,例如将x左移/右移n位,如果x是byte、short、char、int,n会先模32(即n=n%32),然后再进行移位操作。可以这样解释:int类型为32位,移动32位(或以上)没有意义。

同理若x是long,n=n%64。

( 完 )