Java使用位域进行多标记(状态)管理

简介: Android中位域的应用在Android中,我们会经常用到或者看到以下这样的代码 :public class ExampleUnitTest { @Test public void gravityTest(LayoutParams...

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();
    }
}
// 结果
你选择的布局是 : 右下角
你选择的布局是 : 水平居中,竖直向下
你选择的布局是 : 整体居中
你选择的布局是 : 右上角
目录
相关文章
|
3月前
|
Java
Java如何标记异步方法
【8月更文挑战第13天】Java如何标记异步方法
30 1
|
5月前
|
数据采集 监控 前端开发
JAVA公立医院绩效考核管理系统源码-对接HIS数据
在医院的工作和管理上,院领导需要对院内工作人员的工作情况进行了解、评价和监控。 下面将对医院绩效管理系统的HIS数据流程加以阐述。
45 1
JAVA公立医院绩效考核管理系统源码-对接HIS数据
|
4月前
|
JavaScript Java 测试技术
基于Java的人事管理系统设计和实现(源码+LW+部署讲解)
基于Java的人事管理系统设计和实现(源码+LW+部署讲解)
73 7
|
4月前
|
JavaScript Java 测试技术
基于Java的儿童福利院管理系统设计和实现(源码+LW+部署讲解)
基于Java的儿童福利院管理系统设计和实现(源码+LW+部署讲解)
84 7
|
4月前
|
缓存 安全 Java
Java中线程池如何管理?
【7月更文挑战第11天】Java中线程池如何管理?
46 2
|
4月前
|
存储 监控 算法
Java中如何管理内存?
【7月更文挑战第10天】Java中如何管理内存?
55 2
|
4月前
|
算法 Java
Java面试题:解释垃圾回收中的标记-清除、复制、标记-压缩算法的工作原理
Java面试题:解释垃圾回收中的标记-清除、复制、标记-压缩算法的工作原理
54 1
|
4月前
|
设计模式 缓存 安全
Java面试题:工厂模式与内存泄漏防范?线程安全与volatile关键字的适用性?并发集合与线程池管理问题
Java面试题:工厂模式与内存泄漏防范?线程安全与volatile关键字的适用性?并发集合与线程池管理问题
57 1
|
4月前
|
JavaScript 前端开发 Java
Java数字化产科管理系统源码,多家医院应用案例,可直接上项目
Java开发的数字化产科管理系统,已在多家医院实施,支持直接部署。系统涵盖孕产全程,包括门诊、住院、统计和移动服务,整合高危管理、智能提醒、档案追踪等功能,与HIS等系统对接。采用前后端分离架构,Java语言,Vue前端,若依框架,MySQL数据库。优势在于提升就诊效率,降低漏检率,自动报表生成,减少重复工作,支持数据研究,并实现医院与卫计委平台的数据互通,打造全生育周期健康服务。
61 4
|
4月前
|
IDE Java Apache
如何使用Maven管理Java项目依赖
如何使用Maven管理Java项目依赖