众所周知,计算机底层是二进制。而java作为一门计算机编程语言,也对二进制的位运算提供了完整的支持。
在java中,int是32位的,也就是说可以用来实现32位的位运算。方便起见,我们一般用16进制对它赋值,比如: 0011表示成16进制是 0x3, 110111表示成16进制是 0x37。
那么什么是位运算呢?位运算是将数据看做二进制,进行位级别的操作。主要有移位运算和逻辑运算
移位运算:
- 左移:操作符为<<,向左移动,右边的低位补0,左边高位舍弃,将二进制看做整数,左移1位就相当于乘以2。
- 无符号右移:操作符为>>>,向右移动,右边的舍弃掉,左边补0。
- 有符号右移:操作符为>>,向右移动,右边的舍弃掉,左边补的值取决于原来最高位,原来是1就补1,原来是0就补0,将二进制看做整数,右移1位相当于除以2。
10进制转二进制的时候,因为二进制数一般分8位、 16位、32位以及64位 表示一个十进制数,所以在转换过程中,最高位会补零。
在计算机中负数采用二进制的补码表示,10进制转为二进制得到的是源码,将源码按位取反得到的是反码,反码加1得到补码
二进制的最高位是符号位,0表示正,1表示负。
例如:
int a = 4; //100 a = a >> 2; //001, System.out.println("4>>2运算的结果是 :" + a);//变为1 a = 4; //100 a = a << 3; //100000, System.out.println("4<<3运算的结果是 :" + a);//变为32 System.out.println("16>>2运算的结果是 :" + ((16) >> 2));//变为4 System.out.println("-16>>2运算的结果是 :" + ((-16) >> 2));//变为-4 System.out.println("16>>>2运算的结果是 :" + ((16) >>> 2));//变为4 System.out.println("-16>>>2运算的结果是 :" + ((-16) >>> 2));//变为大的整数,看是多少位的
得到结果
可见正数做>>>运算的时候和>>是一样的。区别在于负数运算.
逻辑运算有:
- 按位与 &:两位都为1才为1
- 按位或 |:只要有一位为1,就为1
- 按位取反 ~: 1变为0,0变为1
- 按位异或 ^ :相异为真,相同为假
例如:
int a = ...; a = a & 0x1 // 返回0或1,就是a最右边一位的值。 a = a | 0x1 //不管a原来最右边一位是什么,都将设为1
我们来看几个简单的应用场景:
场景一:判断奇偶
分析:奇数都不是2的整数倍,转换成二进制后最低位必然为1,偶数则相反。利用这个特性我们可以很容易的通过位运算判断一个整数的奇偶性。
看代码:
int i = 1;// 二进制存储方式为00000000000000000000000000000001 int j = 5;// 二进制存储方式为00000000000000000000000000000101 int k = 6;// 二进制存储方式为00000000000000000000000000000110 if ((i & j) == 1) { System.out.println("j的最低位为1,为奇数"); } if ((i & k) == 0) { System.out.println("k的最低位为0,为偶数"); }
场景二:判断一个正整数是不是2的整数次幂
分析:我们先来看一下常见的2的整数次幂的数:2、4、8、16,转化成二进制依次为:10、100、1000、10000,发现规律了没有?那就是除了首位是1,其他全是0。恰巧这些数减去1后等于他们依次按位取反的结果,比如8-1=7,二进制是111,可以通过8的二进制1000按位取反得到。而8&7=0,提取一下规律就是:
(n&(n-1))==0
符合这个规律的n就是2的整数次幂了。