在实际开发中一般不常用到java的位运算,但去看java的一些源码经常会看到这些位运算符,因为运算符的使用对运算效率会有一定的提升,特别是高重复运算,会节约相当的时间开支。
Java位运算符列表如下:
& |
与 |
同为1则为1,其余为0 |
| |
或 |
一个为1则为1,否则为0 |
^ |
异或 |
相同为0,不同为1 |
~ |
非 |
为1则为0,为0则为1 |
<< |
左位移 |
将运算符左边的运算对象向左移动运算符右侧指定的位数(在低位补0) |
>> |
右位移 |
将运算符左边的运算对象向右移动运算符右侧指定的位数。 “有符号”右移位运算符使用了“符号扩展”:若值为正,则在高位插入0;若值为负,则在高位插入1。 |
>>> |
无符号右移 |
无论正负,都在高位插入0 |
在了解位运算之前,先要了解一下二进制的一些表示方法,这里使用的是java语言(注意:在java中是不允许二进制表示的,允许八进制和十六进制)。
数据类型
|
所占位数
|
byte
|
8
|
boolean |
8
|
short |
16
|
int |
32
|
long |
64
|
float |
32
|
double
|
64
|
char |
16
|
System.out.println(Integer.toBinaryString(10));
//打印结果:1010
System.out.println(Integer.toBinaryString(-10));
//打印结果:11111111111111111111111111110110
- 对于正数的转换比较简单,比如上面的10,转换二进制后是00000000000000000000000000001010。
- 但对于负数的转换稍麻烦,转换过程如下:
(一) 接下来再看具体的位运算:
- & 按位与:
举例一:
System.out.println(5&6); //打印结果:4
运算过程:
00000000000000000000000000000101 //5转换二进制
00000000000000000000000000000110 //6转换二进制
00000000000000000000000000000110 //同为1为1,否则为0的原则
4 //转换十进制,结果为4
举例二:
System.out.println(-5&6); //打印结果:2
运算过程:
11111111111111111111111111111011 //-5转二进制
00000000000000000000000000000110 //6转二进制
00000000000000000000000000000010 //同为1为1,否则为0的原则
2 //转十进制,结果为2
- | 按位或:
举例一:
System.out.println(-5|-6); //打印结果:-5
运算过程:
11111111111111111111111111111011 //-5转二进制
11111111111111111111111111111010 //-6转二进制
11111111111111111111111111111011 //一个为1则为1的原则
-5 //转十进制,结果为-5
- ~ 按位非:
举例一:
System.out.println(~-5); //打印结果:4
运算过程:
11111111111111111111111111111011 //-5转二进制
00000000000000000000000000000100 //1为0,0为1原则
4 //转换十进制,结果为4
- ^ 按位异或
举例一:
System.out.println(2^3); //打印结果:1
运算过程:
00000000000000000000000000000010 //2转二进制
00000000000000000000000000000011 //3转二进制
00000000000000000000000000000001 //相同为0,不同为1
1 //转换为十进制,结果为1
- << 左位移
举例一:
System.out.println(5<<3); //打印结果40
运算过程:
00000000000000000000000000000101 //5转二进制
00000000000000000000000000101000 //左移三位,低位补0
40 //转十进制,结果为40
- >> 右位移
举例一:
System.out.println(5>>2); //打印结果1
运算过程:
00000000000000000000000000000101 //5转二进制
00000000000000000000000000000001 //右移两位,高位补0(补符号位数值,正补0,负补1)
举例二:
System.out.println(-5>>2); //打印结果-2
运算过程:
11111111111111111111111111111011 //-5转二进制
11111111111111111111111111111110 //右移两位,高位补1(补符号位数值,正补0,负补1)
- >>> 无符号右移
举例一:
System.out.println(-5>>>2); //打印结果是1073741822
运算过程:
11111111111111111111111111111011 //-5转二进制
00111111111111111111111111111110 //右移两位,高位补0(与符号位无关,统一补0)
写到这里,再回头看为什么会有位运算呢,仔细研究便会发现一些奥妙之处,比如:
System.out.println(2<<2); //打印结果8
System.out.println(2<<3); //打印结果16
System.out.println(2<<4); //打印结果32
有没有发现什么不一样的地方? 推算得出以下公式:Y << N 等于 Y * 2^N(2的N次方)
再比如,我们要求一个整数是奇数,还是偶数,我们可以用按位与,如 N & 1 ,如果得1则表示奇数,0为偶数,当然还有很多,有兴趣的可以深入研究
PS:鉴于可读性考虑,项目中除非必要,还是尽量不使用