月牙旁,你轻颦浅笑

向往的生活也许只是一种波普

O ever youthful, O ever weeping.


位掩码

&(与)~(非)|(或)^(异或)<<(左移位)>>(右移位)这些都是位运算符,在项目中经常使用在状态、权限、标记等功能上。比如有增删改查四种权限,给员工增加其中的一种或几种权限;查看员工是否具备某种权限;删除员工具备的某种权限,这都就可以用位运算符解决。

代码示例

通过位掩码控制员工权限

public class EmployeePermission {

    // 查询权限,二进制第1位,0表示无权限,1表示有权限
    public static final int SEARCH_PERMISSION = 1 << 0; // 0001
    
    // 新建权限,二进制第2位,0表示无权限,1表示有权限
    public static final int ADD_PERMISSION = 1 << 1; // 0010
    
    // 编辑权限,二进制第3位,0表示无权限,1表示有权限
    public static final int EDIT_PERMISSION = 1 << 2; // 0100
    
    // 删除权限,二进制第4位,0表示无权限,1表示有权限
    public static final int DELETE_PERMISSION = 1 << 3; // 1000
    
    // 员工现有权限
    private int employeePermission;

    /**
     *  是否拥某些权限
     */
    public boolean isHavePermission(int permission) {
        return (employeePermission & permission) == permission;
    }

    /**
     *  重新设置权限
     */
    public void ResetPermission(int permission) {
        employeePermission = permission;
    }

    /**
     *  添加一项或多项权限
     */
    public void addPermistion(int permission) {
        employeePermission |= permission;
        // employeePermission += permission; // 效果与上一行代码一致,用或(|)运算符方便从二进制的角度去理解
    }
    
    /**
     *  删除一项或多项权限
     */
    public void delPermistion(int permission) {
        employeePermission &= ~permission;
    }
}

employeePermission 变量二进制的四位数字分别表示员工具有的四种权限状态,每一位的0和1分别表示其中一个权限有无。下面的列表中展示了十进制数对应的转化后的二进制数,以及二进制数字背后分别代表的权限含义。

employeePermission 查询权限 新建权限 编辑权限 删除权限 含义
1(0001) 0 0 0 1 仅拥有删除权限
15(1111) 1 1 1 1 拥有所有四项权限
0(0000) 0 0 0 0 不具有任何权限
6(0110) 0 1 1 0 有用新建与编辑权限

要给员工同时添加「编辑权限」、「查询权限」与「删除权限」,只需下面一条简单的即可实现

employee.addPermistion(EmployeePermission.SEARCH_PERMISSION | EmployeePermission.EDIT_PERMISSION | EmployeePermission.DELETE_PERMISSION);

从上面的代码例子中可以看出,位运算不仅理解简单同时因为二进制代码的位运算属于底层,运算效率很高。若是不用位掩码,那代码会变成什么样子呢?

public class EmployeePermissionOld {
    // 查询权限
    public boolean searchPermission;
    
   // 添加权限
    public boolean addPermission;
    
    // 编辑权限
    public boolean editPermission;
    
    // 删除权限
    public boolean delPermission;

    // get 与 set 方法省略,通过 get 和 set 方法来设置与获取权限
}

这时要给员工同时添加「编辑权限」、「查询权限」与「删除权限」

employee.setSearchPermission(true);
employee.setEditPermission(true);
employee.setDelPermission(true);

经过这样的简单对比会发现使用位掩码还能减少代码数量,让操作看上去更简洁。


位掩码的其他形态

有时候在项目中会看到下面这种写法

#define DEBUG_PROCESS 0x00000001 // 十进制 1 二进制 00000001
#define DEBUG_ONLY_THIS_PROCESS 0x00000002 // 十进制 2 二进制 00000010
#define CREATE_SUSPENDED 0x00000004 // 十进制 4 二进制 00000100
#define DETACHED_PROCESS 0x00000008 // 十进制 8 二进制 00001000
#define CREATE_NEW_CONSOLE 0x00000010 // 十进制 16 二进制 00010000
#define NORMAL_PRIORITY_CLASS 0x00000020 // 十进制 32 二进制 00100000

这种十六进制的表示方式与之前的移位运算的例子道理是一样的,只不过换了种表现形式。在实际项目中用十六进制表示更频繁,这里有使用习惯的差异,同时因为十六进制的一位等于二进制的四位,这让十六进制看起来会更加直观。例如十六进制 0x0FFF 等于二进制的 111111111111(12个1)。