一、Java位运算符
需要注意的是,除一元的~运算符外,所有二元的位运算符优先级都要低于加减乘除算术运算符
符号 | 运算规则 | 二进制码位运算例子 |
---|---|---|
按位与 & | 按位进行与运算 | 0000 0011 & 0001 1101 = 0000 0001 |
按位或 | | 按位进行或运算 | 0000 0011 | 0001 1101 = 0001 1111 |
按位非 ~ | 按位取反 | ~0000 0011 = 1111 1100 |
按位异或 ^ | 按位进行异或运算 | 0000 0011 ^ 0001 1101 = 0001 1110 |
左移运算 << | 二进制数整体左移n位,低位(右侧空位)补0 左移 n 位相当于将一个数乘以 2 的 n 次方(不溢出的情况下)。 | 1110 1100 << 2 = 1011 0000 |
右移运算 >> | 二进制数整体右移n位,正数高位(左侧空位)补0,负数高位补1 右移 n 位相当于将一个数除以 2 的 n 次方并取整(不溢出的情况下)。 | 0001 0100 >> 2 = 0000 0101 1110 1100 >> 2 = 1111 1011 |
无符号右移 >>> | 二进制数整体右移n位,高位(左侧空位)补0 | 1110 1100 >>> 2 = 0011 1011 |
Java位运算符可直接应用于四个基本整数类型(byte,short,int,long)和基本字符型(char)上,这些数据类型在进行位运算时会按照其实际存储的二进制码(整数类型为补码,字符类型为Unicode编码)表示进行计算,得到的结果也是一个二进制码 然后显示时再根据结果类型转换出对应的真值。例:
byte a = 3; //二进制补码:0000 0011
byte b = -2;//二进制补码:1111 1110
int c = a & b;//得到的结果默认为int类型,因为byte和short类型在运算时会自动被提升为int类型
System.out.println(c); //打印结果:2
char c1 = '1';//unicode编码\u0031 二进制00000000 00110001 十进制49
char c2 = '2';//unicode编码\u0032 二进制00000000 00110010 十进制50
int i = c1 | c2;//运算时char自动提升为int类型 运算结果0...0 00110011 十进制为51
char c3 = (char) i;//51对应16进制为0x0033 对应Unicode字符为'3'
System.out.println(c3); //打印结果:3
类型提升问题参考:Java中的自动类型提升与强制类型转换
位运算参考:【详解】位运算符–正数及负数的位运算
二、位运算应用
位运算相对于其他运算计算速率更高,因此合理运用位运算可设计出更高效的程序
1. 权限系统设计
例如某个权限系统共有八项权限,则拥有所有权限的用户的权限码为1111 1111,每一位代表一项权限(0无1有)。用与运算验证权限,例如某个用户的权限码为1101 0110,验证其是否有权限 0010 0000,1101 0110 & 0010 0000 = 0,无此项权限。
参考:Linux文件权限设计
2. 计算散列存储下标
例如在HashMap中计算一个元素的存储下标时最后是通过哈希值和length-1进行与运算,比取余运算更快
(n - 1) & hash
例如容量16的map, length-1即为0000 1111,计算hash值为0101 1101的元素下标:
0000 1111 & 0101 1101 = 0000 1101 即为存储下标