java的位运算符 解析

在实际开发中一般不常用到java的位运算,但去看java的一些源码经常会看到这些位运算符,因为运算符的使用对运算效率会有一定的提升,特别是高重复运算,会节约相当的时间开支。

Java位运算符列表如下:

&

同为1则为1,其余为0

|

一个为1则为1,否则为0

^

异或

相同为0,不同为1

~

1则为0,为0则为1

<< 

左位移

将运算符左边的运算对象向左移动运算符右侧指定的位数(在低位补0

>> 

右位移

将运算符左边的运算对象向右移动运算符右侧指定的位数。有符号右移位运算符使用了符号扩展:若值为正,则在高位插入0;若值为负,则在高位插入1

>>> 

无符号右移

无论正负,都在高位插入0

 

在了解位运算之前,先要了解一下二进制的一些表示方法,这里使用的是java语言(注意:在java中是不允许二进制表示的,允许八进制和十六进制)。

Java整型数据类型有:byte、char、short、int、long。要把它们转换成二进制的原码形式,必须明白他们各占几个字节(一个字节占8位)。 
数据类型
所占位数
byte
8
boolean  
8
short     
16
int
32
long 
64
float
32
double
64
char
16

 

另外二进制中只有0和1,所以正负不是用+ -加减号来表示,而是用最高位数字来表示,0表示正,1表示负,来看两个例子:
System.out.println(Integer.toBinaryString(10));
//打印结果:1010
System.out.println(Integer.toBinaryString(-10));
//打印结果:11111111111111111111111111110110
  1. 对于正数的转换比较简单,比如上面的10,转换二进制后是00000000000000000000000000001010
  2. 但对于负数的转换稍麻烦,转换过程如下:
00000000000000000000000000001010  //取绝对值(10),转换二进制
11111111111111111111111111110101  //取反(反码)
11111111111111111111111111110110  //反码基础上+1(补码)
 

 

(一)   接下来再看具体的位运算:

  • & 按位与:

举例一:

 

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:鉴于可读性考虑,项目中除非必要,还是尽量不使用酷

你可能感兴趣的:(基础)