Java使用位域进行多标记(状态)管理
Android中位域的应用
在Android中,我们会经常用到或者看到以下这样的代码 :
public class ExampleUnitTest { @Test public void gravityTest(LayoutParams params) { // 视图在layout中右下角显示 params.gravity = Gravity.RIGHT | Gravity.BOTTOM; } @Test public void intentFlagTest(Intent intent) { // 清空任务栈中所有旧的activity intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); // 如果activity已存在于栈中,清空该activity之上的所有任务 intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); } @Test public void windowMangerFlags(WindowManager.LayoutParams params) { // 不拦截视图以外的事件,在锁屏中显示 params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; } }
通过一个 int
字段,来添加多个 标志或者状态. 一个int字段,能够管理多个标记(状态)值.
如此神奇的操作怎样实现的呢? 答案就是通过位运算来实现.
位操作基础
java中提供的基础位运算符有 与(&)
,或(|)
,非(~)
,异或(^)
,左移<<
,右移(>>)
和无符号右移(>>>)
.
除了位非(~)
是一元操作符外,其它的都是二元操作符。
下面只介绍本文中,使用到的位操作
- 按位与
A & B : A和B对应的二进制数位都为1时,结果才为1,其他情况为0.
A = 001101 // 13 B = 100101 // 37 A & B = 000101 // 5
- 按位或
A | B : A和B对应的二进制数位都为0时,结果才为0,其他情况为1.
A = 001101 // 13 B = 100101 // 37 A | B = 101101 // 45
- 按位非
~A : 将a的二进制表示每一位进行取反操作,0变1,1变0.
相当于相反数 - 1
A = 001101 // 13 ~A = 11111111111111111111111111110010 // int32位,补码表示,第一位为符号位 // 根据上诉补码转原码为 // 10000000000000000000000000001110 // -14
- 左移操作
A << B:将A的二进制表示的每一位向左移B位,左边超出的位截掉,右边不足的位补0。
在取值范围内,移动一位相当于乘2.
A = 001101 // 13 A << 1 = 011010 // 26
原理与实践
通常情况下,如果多个状态或者标记相互之间有关联, 如布局方向,上下左右,左上,居中 ... 等.我们可能会为每一个标记设置一个变量.
boolean left = false; boolean right = false; ... void setLeft(boolean b); void setRight(boolean b); ...
这种情况下, 有4个标记相互关联,并且能产生新的标记,那么我们就需要设置4个标记变量,然后只能通过一系列的set
方法来转换状态.如
v.setLeft(true); v.setRight(true);
这样就会使得,各个状态不易维护和判断,状态越多,情况越复杂,代码会显得冗长难以维护.
像这种,独立状态(标记)之间相互组合可以产生新的状态(标记),且每个独立状态(标记)只有true
或者false
值的,我们可以使用位域的概念来管理这些状态.
它的核心思想就是将, int 数值看做是 二进制数位表示.如果有四个状态就可以像这样
0000
,用四位二进制表示,每一个二进制位都可以表示一种状态. 然后通过 位运算,来提取或添加标记位.四位对应的组合状态有16个. 而我们,只需要通过一个int变量就能够管理这些状态.
当参与的状态(标记)越多时,如果使用单独的标记变量,就需要生成越多的变量,而用位域,这种独立状态为不管有多少个,都可以用一个变量表示.int类型最多存放32个独立状态
下面我们来看具体实现.(简单的模仿Gravity
类的一部分功能)
public class Gravity { // 二进制表示 0001 public static final int LEFT = 1; // 二进制表示 0010 public static final int RIGHT = LEFT << 1; // 二进制表示 0100 public static final int TOP = LEFT << 2; // 二进制表示 1000 public static final int BOTTOM = LEFT << 3; // 水平居中, 二进制表示 0011 public static final int HORIZONTAL_CENTER = LEFT | RIGHT; // 垂直居中, 二进制表示 1100 public static final int VERTICAL_CENTER = TOP | BOTTOM; // 居中, 二进制表示 1111 public static final int CENTER = HORIZONTAL_CENTER | VERTICAL_CENTER; // 默认左上角, 二进制表示 0101 public static final int DEFAULT = LEFT | TOP; // 存放标志位 private int mFlags = DEFAULT; // 设置标记位,会清除原来的标记 public void setFlags(int flags) { mFlags = flags; } // 添加标记位,在原来的基础上添加 public void addFlags(int flags) { mFlags |= flags; } // 清除指定的标记 public void clearFlags(int flags) { mFlags &= ~flags; } // 清除所有标记,设为默认 public void clears() { mFlags = DEFAULT; } // 判断是否存在指定的标记 public boolean hasFlags(int flags) { return (mFlags & flags) == flags; } // 判断是否 只有指定的标记 public boolean onlyFlags(int flags) { return mFlags == flags; } public void apply() { String des = "左上角"; if (hasFlags(CENTER)) { des = "整体居中"; } else if (hasFlags(HORIZONTAL_CENTER)) { if (hasFlags(BOTTOM)) des = "水平居中,竖直向下"; else des = "水平居中,竖直向下"; } else if (hasFlags(VERTICAL_CENTER)) { if (hasFlags(RIGHT)) des = "竖直居中,水平向右"; else des = "竖直居中,水平向左"; } else if (hasFlags(LEFT | BOTTOM)) { des = "左下角"; } else if (hasFlags(RIGHT | TOP)) { des = "右上角"; } else if (hasFlags(RIGHT | BOTTOM)) { des = "右下角"; } System.out.println("你选择的布局是 : " + des); } }
具体的调用实现 :
public class Main { public static void main(String[] args) { Gravity gravity = new Gravity(); // 设置为 右下角 gravity.setFlags(Gravity.BOTTOM | Gravity.RIGHT); gravity.apply(); // 添加 left后,变为 水平居中,竖直向下 gravity.addFlags(Gravity.LEFT); gravity.apply(); // 判断是否 水平居中, 返回为 true gravity.hasFlags(Gravity.HORIZONTAL_CENTER); // 添加top后,变为 整体居中了 gravity.addFlags(Gravity.TOP); gravity.apply(); // 删掉 bottom和left 之后,变为右上角了 gravity.clearFlags(Gravity.BOTTOM | Gravity.LEFT); gravity.apply(); } } // 结果 你选择的布局是 : 右下角 你选择的布局是 : 水平居中,竖直向下 你选择的布局是 : 整体居中 你选择的布局是 : 右上角
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Java学习----Collection总结
Java----Collection总结 集合,存储多个元素的容器----大小不定。 在集合这块主要的内容有: 接口:CollectionIteratorList SetMap 类:ArrayList LinkedList stackqueue hashMap hashTable 本篇为Collection的总结,才开始学习Java,在集合这块看资料总是感觉一团乱麻。所以写这个总结,一方面把自己知道的东西梳理一下,另一方面初学水平有限,如果有错误还请各位大神能够指点,还有就是刚开始玩社区,希望能够获取一点积分,嘿嘿。希望有一天,能够学习JAVA,加入Ali。 Collection接口 Collection是集合层次的根接口。由于泛型的限制,集合中只能存储对象。泛型只能表示引用类型。 Collection定义中的主要方法,就是说当要实现一个Collection的时候,要先实现以下方法(不全,可以查看API稳定): public interface Collection<E> extends Iterable<E>{ int size(); boolean isEm...
- 下一篇
区块链教程Fabric1.0源代码分析Ledger statedb(状态数据库)-兄弟连区块链
Fabric 1.0源代码笔记 之 Ledger #statedb(状态数据库) 1、statedb概述 statedb,或VersionedDB,即状态数据库,存储了交易(transaction)日志中所有键的最新值,也称世界状态(world state)。可选择基于leveldb或cauchdb实现。 statedb,代码分布在core/ledger/kvledger/txmgmt/statedb目录下,目录结构如下: statedb.go,定义了核心接口VersionedDBProvider、VersionedDB、ResultsIterator和QueryResult,以及UpdateBatch和nsIterator结构体及方法。 util.go,包括工具函数EncodeValue和DecodeValue的实现。 stateleveldb目录,VersionedDBProvider和VersionedDB接口的leveldb版本实现,即stateleveldb.VersionedDBProvider和stateleveldb.versionedDB结构体及方法。 stateco...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- 2048小游戏-低调大师作品
- SpringBoot2整合Redis,开启缓存,提高访问速度
- CentOS关闭SELinux安全模块
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- 设置Eclipse缩进为4个空格,增强代码规范
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- Docker安装Oracle12C,快速搭建Oracle学习环境
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- CentOS7安装Docker,走上虚拟化容器引擎之路