开发技巧:秀儿,如何才能一个字段表示八个状态啊

1、惊现问题

💡 有一天,忽然来了一个需求,问小明提交了哪些课程的做业?java

🌱 A:语文 B:数学 C:英语 D:物理 E:化学 F:生物 G:历史 H:地理 .....

  • 这么多课程.....我要8个字段? 万一还有课程呢?我还要再加字段?bash

  • 我确定不慌啊,我一个字段搞定。工具

2、解决之道

经过一个 int或者long 字段,来添加多个 标志或者状态. 一个int或者long字段,可以管理多个标记(状态)值. 如此神奇的操做怎样实现的呢? 答案就是经过位运算来实现.测试

  • 像这种,独立状态(标记)之间相互组合能够产生新的状态(标记),且每一个独立状态(标记)只有true或者false值的,咱们可使用位状态的概念来管理这些状态.spa

  • 它的核心思想就是将, int 数值看作是 二进制数位表示.若是有四个状态就能够像这样 0000,用四位二进制表示,每个二进制位均可以表示一种状态. 而后经过 位运算,来提取或添加标记位.四位对应的组合状态有16个. 而咱们,只须要经过一个int变量就可以管理这些状态.3d

  • 当参与的状态(标记)越多时,若是使用单独的标记变量,就须要生成越多的变量,而用位域,这种独立状态为无论有多少个,均可以用一个变量表示.int类型最多存放32个独立状态.调试

  • 位操做基础:code

java中提供的基础位运算符有 与(&),或(|),非(~),异或(^),左移<<,右移(>>)无符号右移(>>>).cdn

除了位非(~)是一元操做符外,其它的都是二元操做符。对象

  • 下面只介绍本文中,使用到的位操做:

1.位与

A & B : A和B对应的二进制数位都为1时,结果才为1,其余状况为0.

A     =  001101 // 13
B     =  100101 // 37
A & B =  000101 // 5
复制代码

2.位或

A | B : A和B对应的二进制数位都为0时,结果才为0,其余状况为1.

A     =  001101 // 13
B     =  100101 // 37
A | B =  101101 // 45
复制代码

3.位非

~A : 将a的二进制表示每一位进行取反操做,0变1,1变0.至关于相反数 - 1

A     =  001101 // 13
~A    =  11111111111111111111111111110010 // int32位,补码表示,第一位为符号位
// 根据上诉补码转原码为
//       10000000000000000000000000001110 // -14
复制代码

4.左移操做

A << B:将A的二进制表示的每一位向左移B位, 左边超出的位截掉,右边不足的位补0。在取值范围内,移动一位至关于乘2.

A     =  001101 // 13
A << 1 = 011010 // 26
复制代码

3、实战操做

/** * @author LiJing * @ClassName: BitStatusUtils * @Description: 位运算处理状态的工具类 * @date 2019/9/21 * @time 10:38 */
public class BitStatusUtils {

    //A:语文 B:数学 C:英语 D:物理 E:化学 F:生物 G:历史 H:地理 

    // 二进制表示 0001 没有交任何做业
    public static final int NONE              = 1<<0;   //默认
    public static final int CHINESE           = NONE<<1;//语文
    public static final int MATH              = NONE<<2;//数学
    public static final int ENGLISH           = NONE<<3;//英语
    public static final int PHYSICS           = NONE<<4;//物理
    public static final int CHEMISTRY         = NONE<<5;//化学
    public static final int BIOLOGY           = NONE<<6;//生物
    public static final int HISTORY           = NONE<<7;//历史
    public static final int GEOGRAPHY         = NONE<<8;//地理

    public static final int ALL =NONE|CHINESE|MATH|ENGLISH|PHYSICS|CHEMISTRY|BIOLOGY|HISTORY|GEOGRAPHY;

    /** * @param status 全部状态值 * @param value 须要判断状态值 * @return 是否存在 */
    public static boolean hasStatus(long status, long value) {
        return (status & value) != 0;
    }

    /** * @param status 已有状态值 * @param value 须要添加状态值 * @return 新的状态值 */
    public static long addStatus(long status, long value) {
        if (hasStatus(status, value)) {
            return status;
        }
        return (status | value);
    }

    /** * @param status 已有状态值 * @param value 须要删除状态值 * @return 新的状态值 */
    public static long removeStatus(long status, long value) {
        if (!hasStatus(status, value)) {
            return status;
        }
        return status ^ value;
    }
    
     /**是否交了含有所有状态 * @param status * @return */
    public static boolean hasAllStatus(long status) {
        return (status & ALL) == ALL;
    }

    public static void main(String[] args) {

        long status = addStatus(NONE, CHINESE);
        System.out.println("小明交了语文做业:" + status);

        status = addStatus(status, PHYSICS);
        System.out.println("小明又交了物理做业:" + status);

        status = addStatus(status, HISTORY);
        System.out.println("小明还交了历史做业:" + status);

        status = removeStatus(status, HISTORY);
        System.out.println("小明撤销了历史做业:" + status);

        System.out.println("小明是否交了语文做业:" + hasStatus(status, CHINESE));
        System.out.println("小明是否交了历史做业:" + hasStatus(status, HISTORY));
        System.out.println("小明是否交了生物做业:" + hasStatus(status, BIOLOGY));
        System.out.println("小明是否交了所有做业:" + hasAllStatus(status));
    }
}
复制代码

测试结果:

小明交了语文做业:3
小明又交了物理做业:19
小明还交了历史做业:147
小明撤销了历史做业:19
小明是否交了语文做业:true
小明是否交了历史做业:false
小明是否交了生物做业:false
小明是否交了所有做业:false
复制代码

4、完美小结

  • 内存由字节组成.每一个字节由8位bit组成,每一个bit状态只能是0或1.

  • 所谓位模式,无非就是变量所占用内存的全部bit的状态的序列

  • 运用场景:

    1. 订单实体,咱们可能涉及到的状态有,是否发货,是否审核,是否付款,是否接受等等.
    2. 棋牌游戏用户状态
    3. 棋盘的位图(棋盘模式)位置(域):上下左右 左上角 右上角 左下角 右下角 方位等待
    4. 用户是否提交多项认证资料等
  • 优点:

    1. 占用内存少
    2. 具备高效的拷贝、设值、比较运算等
    3. 位并行运算的可能
  • 不足:

    1. 难于调试
    2. 访问单独位的复杂性,易出错
    3. 难于扩展
    4. 不符合面向对象的风格
    5. 不能处理全部的任务;须要大量的工做
  • 喜欢吗?喜欢就别愣着啊 点赞啊~~ 感谢你们关注我...听说点赞延年益寿哦。
相关文章
相关标签/搜索