BitMask 使用参考
对于 Java 类应用,内存方面需要注意:
- 不要占用大量内存,否则可用内存少;触发 GC 或 - OutOfMemoryError;
- 不要频繁创建对象,频繁内存分配,触发 GC。 
对于枚举和常量:
- 使用枚举,并不会使得对象的创建更加频繁。 
- 枚举类会比常量占用更多的内存,在程序运行期间,如果不卸载枚举类,内存就一直占用着。 - 相对于常量,枚举占用的内存是较为可观的。 
使用常量,可以大量节省内存,在 C 之类的语言中,大量使用 BitMask 来进行状态表示。
在 Android 中,也大量地使用了 BitMask,比如 android.view.View 这个类。
位操作
在使用 BitMask 前,我们先复习一下基本的位操作。
- NOT - NOT 0000 0001
 = 1111 1110
 - 比如: - int a = 1;
 int b = ~a;
 
- OR - OR 0000 0001
 0000 0010
 = 0000 0011
 - 比如: - int a = 1;
 int b = 2;
 int c = a | b;
 
- AND - AND 0000 0101
 0000 0110
 = 0000 0100
 - 比如: - int a = 5;
 int b = 6;
 int c = a & b;
 
BitMask
我们知道,每一个 bit 可以有两种取值:0 或 1。
BitMask 采用一个数值来记录状态,使用这个数值的每一位来表达一个状态。
使用 BitMask 可用非常少的资源表达非常丰富的状态。
在 Java 中,一个 byte 类型,有 8 位(bit),可以表达 8 个不同的状态,并且这些状态是互不影响的。而 int 类型,则有 32 位,可以表达 32 种状态。
更为重要的是,基于 BitMask 可 非常简单地 进行组合状态查询。
BitMask 基本操作
假设我们用一个表示状态的数值: status,初始值为 0。
byte status = 0;
我们定义一个 mask 数值,该数第二位为 1:0000 0010。
我们把 1 往左移动 1 位来得到这个数:
byte mask = 0x01 << 1;
- 设置状态 - 其他位不管,把第 2 位变为 1 即可。 - xxxx xxxx
 OR 0000 0010
 = xxxx xx1x
 - 代码 - status |= mask;
 
- 清除状态 - 其他位不管,把第 2 位置为 0。 - xxxx xxxx
 AND 1111 1101
 = xxxx xx0x
 - 这实际是对 - status和- mask的反码进行逻辑『与』运算:- status &= ~mask;
 
- 查询状态 - 确定第 2 位是 0 还是 1,和 - mask进行逻辑『与』运算:- xxxx xxxx
 AND 0000 0010
 = 0000 00x0
 - 如果为 1,返回一个大于 0 的值,否则返回 0。 - boolean isOn = (status & mask) > 0;
 
例子
下面结合一个例子来做说明。
相关代码在这里: https://github.com/liaohuqiu/android-BitMaskSample。
李白 是个诗人,生活简单『朴素』:有时候写诗;有时候喝酒;有时候边写诗,边喝酒。
不管是忙于写诗还是忙于喝酒,李白都是在忙碌状态中。
我们用一个字节来表示他的状态,一个字节有 8 位,我们从低位起开始取两位分别代表写诗和喝酒。
   writing  ------+
                  |
                  v
     -------+---+---+---+
       x  x |   |   | x |
     -------+---+---+---+
              ^
              |
   drinking --+
两个 mask 为:
// 0000 0010
private static final byte STATE_BUSY_IN_WRITING = 0x01 << 1;
// 0000 0100
private static final byte STATE_BUSY_IN_DRINKING = 0x01 << 2;
- 状态设置与清除 - 以设置 drinking 状态为例子,设置状态即和 mask 值进行逻辑『或』,清除状态与 mask 的反码进行逻辑『与』运算。 - public void setBusyInDrinking(boolean busy) {
 if (busy) {
 mState |= STATE_BUSY_IN_DRINKING;
 } else {
 mState &= ~STATE_BUSY_IN_DRINKING;
 }
 }
 
- 状态查询 - 与 mask 进行逻辑『与』运行,判断是否为零即可: - public boolean isBusyInDrinking() {
 return (mState & STATE_BUSY_IN_DRINKING) != 0;
 }
 
- 组合状态查询 - 不管是忙于写诗还是忙于饮酒,都称为『李白很忙』,这是一种组合状态。只要处于这两种状态中的一种,即处于组合状态中。 - 要进行状态组合,用逻辑『或』运算即可,当进行多个状态组合时,特别方便: - STATE_BUSY_MASK = STATE_BUSY_IN_WRITING | STATE_BUSY_IN_DRINKING
 - 判断是否处于组合状态中: - public boolean isBusy() {
 return (mState & STATE_BUSY_MASK) != 0;
 }
 
Android 中的 IntDef
使用 IntDef 注解来声明常量值,定义变量时,加上 IntDef 所定义的声明,编译器会检查赋值是否合法。
声明:
// 最后 8 位 0000 1100
static final int VISIBILITY_MASK = 0x0000000C;
public static final int VISIBLE = 0x00000000;
// 最后 8 位 0000 0100
public static final int INVISIBLE = 0x00000004;
// 最后 8 位 0000 1000
public static final int GONE = 0x00000008;
@IntDef({VISIBLE, INVISIBLE, GONE})
@Retention(RetentionPolicy.SOURCE)
public @interface Visibility {}
使用:
public void setVisibility(@Visibility int visibility) {
    setFlags(visibility, VISIBILITY_MASK);
}
上面我们看到,代码中采用了最左的 3,4 位来表达 View 的可见性。
结论
除了 IntDef,还有 StringDef,有兴趣的同学可以看源码。
在 Android 的代码中有大量的 BitMask 的运用,像 View,MotionEvent 这样的核心基础类中,需要认真考虑内存的使用,能省则省。
如果你真想完全地掌控内存的使用,追求卓越的品质,想最大限度节省内存,BitMask 是你不错的选择。
同时,我们也应该清楚枚举也不是不能用。
我听到过很多论调,说用『枚举不好,官方也建议别用,因为占用很多内存,效率不高』,这些也都是人云亦云的典型。
实际上,除非你写的是类似 View 这样的核心基础类或者超大型应用,否则,如果连枚举这样内存开销都有问题的话,这个项目的问题就真的大了。
BitMask 使用参考的更多相关文章
- Hyper-v 安装CentOS 7 (其他虚拟机一样参考)
		平台之大势何人能挡? 带着你的Net飞奔吧!http://www.cnblogs.com/dunitian/p/4822808.html hyper-v安装很多人没弄过,我这里介绍一下.(其他虚拟机参 ... 
- ifconfig: command not found(CentOS专版,其他的可以参考)
		ifconfig: command not found 查看path配置(echo相当于c中的printf,C#中的Console.WriteLine) echo $PATH 解决方案1:先看看是不是 ... 
- 参考bootstrap中的popover.js的css画消息弹框
		前段时间小颖的大学同学给小颖发了一张截图,图片类似下面这张图: 小颖当时大概的给她说了下,其实小颖也不知道上面那个三角形怎么画嘻嘻,给她说了DOM结构,具体的css让她自己百度,今天小颖自己参考boo ... 
- Oracle安装部署,版本升级,应用补丁快速参考
		一.Oracle安装部署 1.1 单机环境 1.2 Oracle RAC环境 1.3 Oracle DataGuard环境 1.4 主机双机 1.5 客户端部署 二.Oracle版本升级 2.1 单机 ... 
- Angularjs参考框架地址
		1.Table(Grid)参考地址 https://github.com/samu/angular-table https://github.com/daniel-nagy/md-data-table ... 
- iOS开发之三个Button实现图片无限轮播(参考手机淘宝,Swift版)
		这两天使用Reveal工具查看"手机淘宝"App的UI层次时,发现其图片轮播使用了三个UIButton的复用来实现的图片循环无缝滚动.于是乎就有了今天这篇博客,看到“手机淘宝”这个 ... 
- SQL 性能调优中可参考的几类Lock Wait
		在我们的系统出现性能问题时,往往避不开调查各种类型 Lock Wait,如Row Lock Wait.Page Lock Wait.Page IO Latch Wait等.从中找出可能的异常等待,为性 ... 
- RMAN异机恢复快速参考
		应用场景:服务器A为正常运行的生产环境,需要在服务器B上部署一套相同环境做测试. 数据库环境:RHEL6.4 + Oracle 11.2.0.4.7 一. 服务器A备份数据库 1.1 在线备份(数据库 ... 
- Linux平台oracle 11g单实例 安装部署配置 快速参考
		1.重建主机的Oracle用户 组 统一规范 uid gid 以保证共享存储挂接或其他需求的权限规范 userdel -r oracle groupadd -g 7 oinstall groupadd ... 
随机推荐
- Oracle 表的连接方式(2)-----HASH JOIN的基本机制2
			Hash算法原理 对于什么是Hash算法原理?这个问题有点难度,不是很好说清楚,来做一个比喻吧:我们有很多的小猪,每个的体重都不一样,假设体重分布比较平均(我们考虑到公斤级别),我们按照体重来分,划分 ... 
- 用Redis bitmap统计活跃用户、留存
			Spool的开发者博客,描述了Spool利用Redis的bitmaps相关的操作,进行网站活跃用户统计工作. 原文:http://blog.getspool.com/2011/11/29/fast-e ... 
- MySQL Server-id的作用
			1. mysql同步的数据中是包含server-id的,用于标识该语句最初是从哪个server写入的,因此server-id一定要有的 2. 每一个同步中的slave在master上都对应一个mast ... 
- Win7任务计划自由预设系统定时自动关机
			大家在使用电脑的时候可能会遇到一些需要无人值守让电脑自行执行任务后定时关机的情形,在Win7系统中,我们可以使用"任务计划"设置功能结合shutdown命令灵活设置任务计划,让Wi ... 
- android----sqlite中的 query() 参数分析
			public Cursor query (String table, String[] columns, String selection, String[] selectionArgs, Strin ... 
- Linq to XML 之XElement的Descendants方法的新发现
			C#操作XML的方法有很多,但个人认为最方便的莫过于Linq to XML了,特别是XElement的Descendants方法是我最常用的一个方法. 这个方法可以根据节点名(Name)找到当前调用的 ... 
- [问题]C# 结构体对齐:如何将变长byte数组对齐
			[StructLayout(LayoutKind.Sequential,Pack=1)] struct Report_Read_Parameter { byte Confirmation; byte ... 
- 让站长在SEO时更得心应手的六个细节
			分析一下SEO的心得,希望能对很多做网站优化和做网站推广的站长有帮助,现在做SEO的人越来网站推广越多,即使很多人在做,但不知道自己能否成功,自己的优化是否会见效,所以在这里还是来分享一下咱们在SEO ... 
- redis window环境下的安装地址
			https://github-cloud.s3.amazonaws.com/releases/3402186/25358446-c083-11e5-89cb-61582694855e.zip?X-Am ... 
- 剑指offer--面试题10--相关
			题目一:判断一个整数是不是2的n次幂 实现大概如下: int main() { ; )) == ) //重要!! std::cout<<"YES!"<<st ... 
