news 2026/6/12 19:18:57

位掩码的思考

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
位掩码的思考

位掩码的思考







第一章 一堆废话

第01节 引子

最近两天在写代码的过程中,使用到了 定位功能,在集成了 三方SDK 的过程中,我发现,需要申请多个权限,多个权限全部通过的情况下,才能完成这个功能。

接下来,我一顿操作猛如虎,写了三个权限的申请。如: 我想要完成定位,我需要三个权限

  • 精准定位
  • 内部存储
  • 后台弹窗

也就是说 我需要 三个权限,全部通过,我才能正常使用我的软件! 只要有一个没有通过,将无法使用。



我考虑到别人做权限校验的过程中,出现了 红叉 绿勾 标注清楚的情况。如图:

如果常规的做法很简单,多个 boolean 值,直接判断一下,就可以了。但是如果增加了条件呢?

如何处理,能否用一个数据去记录 当前哪些权限开启了,哪些权限未开启?



我在想 如果我写了一个 函数方法,用于校验所有的权限。checkPermissions()反馈一个值给外部调用者,

外部只需要通过一个值,就明确知晓什么权限开启了,什么权限未开启。

我也在想,如果这个值,可以通过网络传输 或者 本地数据库记录。能否用一个值,完整的记录下来这个内容呢?

以前的想法,很可能就是写一个boolean[]布尔数组,记录下来哪些权限是开启的,哪些权限是关闭的。

但是目前我就想使用一个数据值,去记录多个状态。 这里的想法!



突然!我想到了 Linux 操作系统 中 文件权限管理chmod 775 myscript.sh

我就想 我们能否用一个 整数,它的二进制位数,去表示当前的权限选择呢。0000_0000_0000_0000_1111_0101_0000_0000



这样的数据中,不就是 由01去表示的 权限位。(0是不允许,1是允许)

如果我最开始的时候,就约定了 3号位置代表是 “精确定位” 5号位置代表是 “内部存储” 6号位置代表是 “后台弹窗”

通过对应位置的 0 和 1 确定这个是否被授权。 好像也可以啊!

然后我将整个 0和1 组成的数据,转换成为一个十进制的数据,进行存储(数据库) 或者 传输(网络)相比之下是不是 比 传递一堆的数据更小更快!

好像是可以的!



通过前面的介绍,我试着找了相关的资料,知晓了这种方案,有个专属的名词 【位掩码

专业的定义:位掩码(Bitmask)是计算机科学中一种利用二进制位(0 和 1)来高效记录、修改和查询多个开关状态(或布尔条件)的技术。




第02节 理解

既然前面知道了 位掩码,那么我们能不能更直观的从 人的角度,去看待应用位掩码,帮我们做事情呢?



为了更好的去学习 位掩码,我想到了一个相对而言,比较贴合的例子。

现实生活中,如果 您会下象棋,应该知道象棋一共有 32颗 棋子。 他们分别是



能否用一个 int 类型的数据,来表示整个棋盘中,棋子的存活呢? 存在是 1, 不存在是 0

因为 int 类型的数据正好是 32位,下面是我用 Java 代码,定义的数据。

为了方便于大家理解这段代码的意思,我采用 xlsx 来表示内容。

也就是说,我们采用给个位数,表示了每一颗 棋子的 存活状态。







第二章 案例代码

第01节 位掩码的工具类

包含有 5 个方法

序号方法名称方法作用举例说明
1int addData(int currentMask, int targetData)添加数据参数1:当前模板
参数2:十进制数
2int removeData(int currentMask, int targetData)删除数据参数1:当前模板
参数2:十进制数
3boolean containsData(int currentMask, int targetData)判断模板中存在数据参数1:当前模板
参数2:十进制数
4List<String> maskToAvailableList(int currentMask, Map<String, Integer> businessMap)转换 十进制 转 映射值参数1:当前模板
参数2:映射表
5String to32BitString(int number)将十进制数据
转换为二进制字符串
参数:十进制数据



代码

importjava.util.ArrayList;importjava.util.List;importjava.util.Map;publicclassBitmaskUtil{/** * 1. 添加数据(将某位置为 1) * 对应业务:棋子入场、开启某权限、记录某数据存在 * 换算公式:currentMask | targetData */publicstaticintaddData(intcurrentMask,inttargetData){returncurrentMask|targetData;}/** * 2. 剔除数据(将某位置为 0) * 对应业务:棋子死亡离场、关闭某权限、擦除某数据 * 换算公式:currentMask & ~targetData */publicstaticintremoveData(intcurrentMask,inttargetData){returncurrentMask&~targetData;}/** * 3. 检查数据是否存在/存活(判断某位是否为 1) * 换算公式:(currentMask & targetData) == targetData */publicstaticbooleancontainsData(intcurrentMask,inttargetData){return(currentMask&targetData)==targetData;}/** * 4. 转换数据:【十进制整数 -> 存活数据列表】 * 传入标准的业务字典(配置表),解析出当前整数里到底活着哪些数据 * * @param currentMask 当前的十进制掩码 * @param businessMap 业务配置字典(Key为数据名称,Value为位权重如 1, 2, 4, 8...) */publicstaticList<String>maskToAvailableList(intcurrentMask,Map<String,Integer>businessMap){List<String>activeList=newArrayList<>();for(Map.Entry<String,Integer>entry:businessMap.entrySet()){if(containsData(currentMask,entry.getValue())){activeList.add(entry.getKey());}}returnactiveList;}/** * 5. 辅助工具:获取精细的 32 位二进制字符串(高位补0),便于调试观察 */publicstaticStringto32BitString(intnumber){returnString.format("%32s",Integer.toBinaryString(number)).replace(' ','0');}}




第02节 映射规范类

importjava.util.LinkedHashMap;importjava.util.Map;/** * 映射的规范,业务规范 */publicclassSpecification{// 业务配置表publicstaticfinalMap<String,Integer>configurationTable=newLinkedHashMap<>();// ========================================================// 1. 黑方 16 枚棋子位定义(交换后:占据低 16 位,即 1 << 0 到 1 << 15)// ========================================================// --- 底线 (九个位置) ---publicstaticfinalintB_JU_LEFT=1<<0;// 黑左车publicstaticfinalintB_MA_LEFT=1<<1;// 黑左马publicstaticfinalintB_XIANG_LEFT=1<<2;// 黑左象publicstaticfinalintB_SHI_LEFT=1<<3;// 黑左士publicstaticfinalintB_JIANG=1<<4;// 黑将 (居中无左右)publicstaticfinalintB_SHI_RIGHT=1<<5;// 黑右士publicstaticfinalintB_XIANG_RIGHT=1<<6;// 黑右象publicstaticfinalintB_MA_RIGHT=1<<7;// 黑右马publicstaticfinalintB_JU_RIGHT=1<<8;// 黑右车// --- 炮线 (两个位置) ---publicstaticfinalintB_PAO_LEFT=1<<9;// 黑左炮publicstaticfinalintB_PAO_RIGHT=1<<10;// 黑右炮// --- 卒线 (五个位置) ---publicstaticfinalintB_ZU_1=1<<11;// 黑卒1publicstaticfinalintB_ZU_2=1<<12;// 黑卒2publicstaticfinalintB_ZU_3=1<<13;// 黑卒3 (居中)publicstaticfinalintB_ZU_4=1<<14;// 黑卒4publicstaticfinalintB_ZU_5=1<<15;// 黑卒5// ========================================================// 2. 红方 16 枚棋子位定义(交换后:占据高 16 位,即 1 << 16 到 1 << 31)// ========================================================// --- 底线 (九个位置) ---publicstaticfinalintR_JU_LEFT=1<<16;// 红左车publicstaticfinalintR_MA_LEFT=1<<17;// 红左马publicstaticfinalintR_XIANG_LEFT=1<<18;// 红左相publicstaticfinalintR_SHI_LEFT=1<<19;// 红左仕publicstaticfinalintR_SHUAI=1<<20;// 红帅 (居中无左右)publicstaticfinalintR_SHI_RIGHT=1<<21;// 红右仕publicstaticfinalintR_XIANG_RIGHT=1<<22;// 红右相publicstaticfinalintR_MA_RIGHT=1<<23;// 红右马publicstaticfinalintR_JU_RIGHT=1<<24;// 红右车// --- 炮线 (两个位置) ---publicstaticfinalintR_PAO_LEFT=1<<25;// 红左炮publicstaticfinalintR_PAO_RIGHT=1<<26;// 红右炮// --- 兵线 (五个位置) ---publicstaticfinalintR_BING_1=1<<27;// 红兵1publicstaticfinalintR_BING_2=1<<28;// 红兵2publicstaticfinalintR_BING_3=1<<29;// 红兵3 (居中)publicstaticfinalintR_BING_4=1<<30;// 红兵4publicstaticfinalintR_BING_5=1<<31;// 红兵5static{// === 填充黑方 ===configurationTable.put("黑左车",B_JU_LEFT);configurationTable.put("黑左马",B_MA_LEFT);configurationTable.put("黑左象",B_XIANG_LEFT);configurationTable.put("黑左士",B_SHI_LEFT);configurationTable.put("黑将",B_JIANG);configurationTable.put("黑右士",B_SHI_RIGHT);configurationTable.put("黑右象",B_XIANG_RIGHT);configurationTable.put("黑右马",B_MA_RIGHT);configurationTable.put("黑右车",B_JU_RIGHT);configurationTable.put("黑左炮",B_PAO_LEFT);configurationTable.put("黑右炮",B_PAO_RIGHT);configurationTable.put("黑卒1",B_ZU_1);configurationTable.put("黑卒2",B_ZU_2);configurationTable.put("黑卒3",B_ZU_3);configurationTable.put("黑卒4",B_ZU_4);configurationTable.put("黑卒5",B_ZU_5);// === 填充红方 ===configurationTable.put("红左车",R_JU_LEFT);configurationTable.put("红左马",R_MA_LEFT);configurationTable.put("红左相",R_XIANG_LEFT);configurationTable.put("红左仕",R_SHI_LEFT);configurationTable.put("红帅",R_SHUAI);configurationTable.put("红右仕",R_SHI_RIGHT);configurationTable.put("红右相",R_XIANG_RIGHT);configurationTable.put("红右马",R_MA_RIGHT);configurationTable.put("红右车",R_JU_RIGHT);configurationTable.put("红左炮",R_PAO_LEFT);configurationTable.put("红右炮",R_PAO_RIGHT);configurationTable.put("红兵1",R_BING_1);configurationTable.put("红兵2",R_BING_2);configurationTable.put("红兵3",R_BING_3);configurationTable.put("红兵4",R_BING_4);configurationTable.put("红兵5",R_BING_5);}}




第03节 测试类

如何使用上述的几个方法呢?

importjava.util.List;publicclassDemo{publicstaticvoidmain(String[]args){intFULL=0XFFFF_FFFF;intZERO=0X0000_0000;// 在空棋盘当中, 放入了两个数据(红左车 和 红帅) 返回的结果是一个十进制的整数intaddData=BitmaskUtil.addData(ZERO,Specification.R_JU_LEFT+Specification.R_SHUAI);// 输出当前的十进制整数System.out.println("addData = "+addData);// 将十进制的整数, 转换成为二进制的数据(32位的0和1组成) 如果存在是1, 如果不存在是 0Stringstr32add=BitmaskUtil.to32BitString(addData);// 输出当前的二进制System.out.println("str32add = "+str32add);// 将当前的数据, 转换成为映射中存在的数据值, 从映射表当中查找 存在的数据值List<String>listAdd=BitmaskUtil.maskToAvailableList(addData,Specification.configurationTable);// 输出当前的映射值System.out.println("listAdd = "+listAdd);System.out.println("==================================");// 在满棋盘当中, 移除掉数据(红帅 和 红右士) 返回的结果是一个十进制的整数intremoveData=BitmaskUtil.removeData(FULL,Specification.R_SHUAI+Specification.R_SHI_RIGHT);// 输出当前的十进制System.out.println("removeData = "+removeData);// 将十进制的整数, 转换成为二进制的数据(32位的0和1组成) 如果存在是1, 如果不存在是 0Stringstr32remove=BitmaskUtil.to32BitString(removeData);// 输出当前的二进制System.out.println("str32remove = "+str32remove);// 将当前的数据, 转换成为映射中存在的数据值, 从映射表当中查找 存在的数据值List<String>listRemove=BitmaskUtil.maskToAvailableList(removeData,Specification.configurationTable);// 输出当前的映射值System.out.println("listRemove = "+listRemove);// 查找当前的数据中, 是否包含有 需要查找的数据booleancontainsData=BitmaskUtil.containsData(removeData,Specification.R_SHUAI);// 输出查找的结果System.out.println("containsData = "+containsData);}}




第04节 最终输出结果

addData = 1114112 str32add = 00000000000100010000000000000000 listAdd = [红左车, 红帅] ================================== removeData = -3145729 str32remove = 11111111110011111111111111111111 listRemove = [黑左车, 黑左马, 黑左象, 黑左士, 黑将, 黑右士, 黑右象, 黑右马, 黑右车, 黑左炮, 黑右炮, 黑卒1, 黑卒2, 黑卒3, 黑卒4, 黑卒5, 红左车, 红左马, 红左相, 红左仕, 红右相, 红右马, 红右车, 红左炮, 红右炮, 红兵1, 红兵2, 红兵3, 红兵4, 红兵5] containsData = false







第三章 后续操作

第01节 拓展

关于后续,如果作为一个应用而言,我们只需要1、拿着工具类, 2、根据自己的业务,自定义配置项,应该就可以完成大部分的 实际需求。



例如:

前面我定义的几个条件,当然可能会更多。

  • 精准定位
  • 内部存储
  • 后台弹窗

就可以修改配置项,作为条件,直接采用工具类,应该是可以完成对应的 位掩码权限管理。




第02节 深思

方向1:

如果我们想要深入的理解,整个操作,那么可以专门去研究一下位运算的操作。 也就是关于工具类中的几个 运算符。

方向2:

如果我没有那么多的条件选项,我该如何呢? 或者说,我改为 16位的 short 甚至是 8位的 byte 亦或者是 64 位的 long

方向3:

当前我写的是 Java 的版本,如果我们操作的其他的语言呢? 例如 C语言,C++等。







版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/12 19:14:54

终极指南:用Get cookies.txt LOCALLY实现安全高效的Cookie管理

终极指南&#xff1a;用Get cookies.txt LOCALLY实现安全高效的Cookie管理 【免费下载链接】Get-cookies.txt-LOCALLY Get cookies.txt, NEVER send information outside. 项目地址: https://gitcode.com/gh_mirrors/ge/Get-cookies.txt-LOCALLY 在当今Web开发和测试工作…

作者头像 李华
网站建设 2026/6/12 19:11:52

宝塔面板实现Nginx反向代理与负载均衡(Docker版)

文章目录一、前言二、实验环境三、环境准备&#xff08;宝塔 Docker&#xff09;四、Docker 部署两个后端 Nginx 容器五、宝塔配置 Nginx 负载均衡六、功能验证七、常见问题与解决方案八、核心知识点总结九、总结与心得一、前言 在搭建个人博客或部署微服务时&#xff0c;我们…

作者头像 李华
网站建设 2026/6/12 19:10:17

MC68HC16Z2 QSM模块详解:QSPI队列与SCI串口实战配置指南

1. 项目概述&#xff1a;深入MC68HC16Z2的串行通信心脏在嵌入式系统开发&#xff0c;尤其是基于经典MC68HC16系列微控制器的项目中&#xff0c;高效、可靠的串行通信往往是连接传感器、执行器、存储器和上位机的生命线。很多工程师在初次接触这类老牌MCU的串行模块时&#xff0…

作者头像 李华
网站建设 2026/6/12 19:09:45

DSP56602:低功耗移动通信中的16位定点DSP架构与设计哲学

1. 项目概述&#xff1a;一款为低功耗移动通信而生的DSP在嵌入式系统&#xff0c;尤其是对功耗和成本都极为敏感的数字蜂窝移动终端&#xff08;比如早期的功能手机&#xff09;设计中&#xff0c;选择一颗合适的处理器是项目成败的关键。这类应用场景对处理器的要求非常苛刻&a…

作者头像 李华
网站建设 2026/6/12 18:57:52

存在主义焦虑的庖丁解牛

它的本质是&#xff1a;**存在主义焦虑不是病理性的恐惧&#xff0c;而是 人类意识觉醒后的必然副作用 (Inevitable Side Effect of Conscious Awakening)。 核心矛盾&#xff1a;人类渴望 确定性 (Certainty)、目的 (Purpose) 和 永恒 (Eternity)&#xff0c;但宇宙提供的是 偶…

作者头像 李华