java中的位运算--与(&)、或(|)、非(~)、异或(^) 2019-07-21 程序之旅 暂无评论 883 次阅读 ## java中的位运算--与(&)、或(|)、非(~)、异或(^) 简单的了解一下java中提供的位移运算符与逻辑运算符。主要是在一些使用场景中,使用位运算符替代其他的运算操作,能调高程序的执行效率,例如取余操作。先知道什么是java中的与、或、非、异或操作,之后再简单的举个编程中的例子。 ### 运算符的使用 #### 与操作 在数字逻辑课程中,与操作就是二进制中两个位数同时为1的时候,结果为1。 ``` 1&1 = 1 1&0 = 0 0&1 = 0 0&0 = 0 ``` 代码实现 ```java package com.felton.bit.and; public class AndOperation { public static void main(String[] args) { int data1 = 1; int data2 = 0; int result = data1&data2; System.out.println("the data1 "+data1+" is " +Integer.toBinaryString(data1)); System.out.println("the data2 "+data2+" is " +Integer.toBinaryString(data2)); System.out.println("the result "+result+" is " +Integer.toBinaryString(result)); } } ``` #### 或操作 或操作是当两个二进制数字中,有一个数字为1的时候,结果为1。 ``` 1|1 = 1 1|0 = 1 0|1 = 1 0|0 = 0 ``` 代码实现 ```java package com.felton.bit.or; public class OrOperation { public static void main(String[] args) { int data1 = 1; int data2 = 0; // 或运算 int result = data1|data2; System.out.println("the data1 "+data1+" is " +Integer.toBinaryString(data1)); System.out.println("the data2 "+data2+" is " +Integer.toBinaryString(data2)); System.out.println("the result "+result+" is " +Integer.toBinaryString(result)); } } ``` #### 非操作 对二进制数字进行取反操作 ``` ~1 = 0 ~0 = 1 ``` 代码实现 ```java package com.felton.bit.non; public class NonOperation { public static void main(String[] args) { int data1 = 1; int data2 = 0; // 非运算 int result1 = ~data1; int result2 = ~data2; System.out.println(Integer.toBinaryString(result1)); System.out.println(Integer.toBinaryString(result2)); } } ``` > 因为在java中int类型数据是32位,所以在取反操作时,高位的0也要取反 > > 1111 1111 1111 1111 1111 1111 1111 1110 // int 1取反 > 1111 1111 1111 1111 1111 1111 1111 1111 // int 0 取反 #### 异或操作 两个二进制运算不相同的情况下,结果为1。 ``` 1^0 = 1 0^1 = 1 1^1 = 0 0^0 = 0 ``` 代码实现 ```java package com.felton.bit.xor; public class XorOperation { public static void main(String[] args) { int data1 = 1; int data2 = 0; // 异或运算 int result = data1^data2; System.out.println("the data1 "+data1+" is " +Integer.toBinaryString(data1)); System.out.println("the data2 "+data2+" is " +Integer.toBinaryString(data2)); System.out.println("the result "+result+" is " +Integer.toBinaryString(result)); } } ``` ### 位移运算符 位移运算符有四个,其中两是无符号位移,另外两个是有符号位移。 #### 有符号运算符(有符号右移动>> 有符号左移动<<) 在int类型中,第31位表示符号类型,0表示正数,1表示负数。而有符号运算就是保持31位的数字不变,而移动其他的31个二进制数字(二进制以0开始,第31位为最高位) ##### 有符号移动 如果符号都是正数(也就是31位0),这左移动或右移动都补0。如果符号位是负数(31位为1),则右移动高位补1,左移动低位补0。 ```F# // 正数移动 the data 2 is 10 the result1 1 is 1 the result2 4 is 100 // 负数移动 the data -2 is 11111111111111111111111111111110 the result1 -1 is 11111111111111111111111111111111 the result2 -4 is 11111111111111111111111111111100 ``` > -2 的二进制表达是`11111111111111111111111111111110`,是2的补码,也就是2进制的反码(`11111111111111111111111111111101`)低位加一得到。 ##### 无符号移动 无符号右移动(不存在左移动),高位符号为1时补1,高位符号为0时补0; ```f# // 高位为0 the data 5 is 101 the result3 2 is 10 // 高位为1时 the data -5 is 11111111111111111111111111111011 the result3 2147483645 is 1111111111111111111111111111101 ``` 实现代码 ```java package com.felton.bit.bit_move; public class BitMove { public static void main(String[] args) { int data = -5; // 有符号移动 int result1 = data>>1; int result2 = data<<1; // 无符号移动 int result3 = data >>> 1; System.out.println("the data "+data+" is " +Integer.toBinaryString(data)); System.out.println("the result1 "+result1+" is " +Integer.toBinaryString(result1)); System.out.println("the result2 "+result2+" is " +Integer.toBinaryString(result2)); System.out.println("the result3 "+result3+" is " +Integer.toBinaryString(result3)); } } ``` #### 小甜点 过去取模(取余)的时候使用的是`%`符号,如果使用的是关系运算,代码效率会更高一些。 ```java System.out.println("the 345 % 16 is "+(345%16) + " or " + (345&(16-1))); ``` 补充,盗用别人的总结 | 运算符分类 | 结合顺序 | 运算符 | | :--------------------: | :------: | :---------------------------------------------------: | | 分隔符 | 左结合 | . [] ( ) ; , | | 一元运算符 | 左结合 | ! ++ -- - ~ | | 算术运算符 移位运算符 | 左结合 | * / % + - << >> >>> | | 关系运算符 | 左结合 | < > <= >= instanceof(Java 特有) = = != | | 逻辑运算符 | 左结合 | ! && | | 三目运算符 | 左结合 | 布尔表达式?表达式1:表达式2 | | 赋值运算符 | 左结合 | = *= /= %= += -= <<= >>= >>>= &= *= | > 优先级,自上而下,由高而低 ### 简单运算符的使用 这里举了简单的例子来熟悉去运算符的使用,该例子主要是解决用户授权的问题,例如授权问题中,如果需要添加用户的权限选项,或清除用户的某个权限,或判断用户是否存在某个权限,如果是使用if else来权限的一个一个判断,无疑是不合实际的。一是因为会动态的添加权限类中的成员变量,时间长了会使得成员变量的得很多,而显得代码很乱;而是如果新增一个权限项目,在判断权限是否存在时就得添加一个if语句进行判断,代码效率非常低,而且在编程过程中尽量不要出现超过3个以上的if判断语句。 ```java package utile; public class Permission { public static final int ALLOW_SELECT = 1 << 0; // 0001 = 1 查询操作 public static final int ALLOW_INSERT = 1 << 1; // 0010 = 2 插入操作 public static final int ALLOW_UPDATE = 1 << 2; // 0100 = 4 更新操作 public static final int ALLOW_DELETE = 1 << 3; // 1000 = 8 删除操作 private int flag; // 权限标志 private void setPer(int per){ flag = per; } private int getPer(){ return flag; } public void enable(int per){ flag = flag|per; } // 移除用户的权限 public void disable(int per){ flag = flag&~per; } // 判定用户的权限 public boolean isAllow(int per){ return ((flag&per) == per); } // 判定用户的没有权限 public boolean isNotAllow(int per){ return ((flag&per) == 0); } public static void main(String[] args) { int flag = 15; Permission permission = new Permission(); permission.setPer(flag); permission.disable(ALLOW_DELETE|ALLOW_INSERT); System.out.println("bin = " + Integer.toBinaryString(permission.getPer())); System.out.println("select = "+permission.isAllow(ALLOW_SELECT)); System.out.println("update = "+permission.isAllow(ALLOW_UPDATE)); System.out.println("insert = "+permission.isAllow(ALLOW_INSERT)); System.out.println("delete = "+permission.isAllow(ALLOW_DELETE)); } } ``` ---- ### 2019年10月2日 这里还有一种判断权限的方法,由于位移运算符的1往左边移动一位,表示2的指数加一,所以可以表示 ``` flag & Math.pow(2, per) == 0 ``` 当等式返回为true时,表示flag存在权限per。 例如:flag拥有所有的权限,十进制表示15,二进制表示1111,所有的权限依次下来使用的是一个十进制表示,分别是0、1、2和3, - 0:查询操作 - 1:插入操作 - 2:更新操作 - 3:删除操作 四个操作权限,如果是更新权限`ALLOW_UPDATE`,十进制是2,使用如下的操作能判断是否存在指定的权限 ``` flag & (int)Math.pow(2, per) == 0 ``` 如果操作是为true,则表示可以不存在该权限。22=4 --> 0100,所以与上1111后还是等于0100,不为0,得出存在该权限,相比我之前方法,该方法使用一个顺序的形式来表示权限,从0开始逐渐加1,便于记忆和更改。唯一不好的就是每次判断的时候都得进行一次计算。 打赏: 微信, 支付宝 标签: 位运算, 权限控制 本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。