ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

项目二进制标位实战应用

2020-05-01 11:54:30  阅读:258  来源: 互联网

标签:实战 0000 tags 二进制 System value int tag 标位


四月已过大半,紧急补上一篇博客,本文将讲解二进制状态位在项目中的实战应用,技术原理很简单,就是利用二级制与位运算实现。这种方式的应用场景还是比较广泛,希望对你有用~

本文首发于个人博客:http://nullpointer.pw/binary-tag.html

前言


举个栗子,需要保存这些状态你会怎么设计表呢?

你可能会想,这很简单啊,针对一个开关加一个状态字段嘛~

呵呵真是太年轻,这样开发上线后,产品又要增加新的提醒方式,如图

难不成,再加状态字段?

可以发现,以上这种做法,在需求改动时就会很蛋疼,而且这只是提醒的开关设置,若有其他类型的开关设置就更加麻烦。

所以这里引入今天的主题,二进制状态位。

二进制与位运算

这样数据库只需要添加一个整数字段保存即可。使用2的次幂值代表一种状态,比如使用 1(2º) 代表开启站内提醒,2(2¹) 代表 开启邮件提醒,4(2²) 代表开启短信提醒等等,这样这个状态位字段只需要存储 6即可表示已开启这几项提醒。因为 6 与这几个状态值进行与运算时都等于状态值本身,如果不等于则为开启。

首先回顾一下二进制与位运算的基础知识

十进制 二进制
0 0000 0000
1 0000 0001
2 0000 0010
3 0000 0011
4 0000 0100
5 0000 0101
6 0000 0110
7 0000 0111

或运算:bit位上有1为1。例如:2 | 1 == 0000 0010 | 0000 0001 == 3
与运算:bit位都为1才为1。 例如 5 & 2 == 0000 0101 & 0000 0010 == 0

实际应用

以上文提醒开关为例:
现在打开 站内提醒,不打开右键提醒,打开短信提醒,最终的值的计算方法为:
1 | 4 = 5

/**
 *  计算状态位
 *  tags: 已有状态位
 *  value: 需要添加的状态值
 */
public static int addTag(int tags, int... values) {
  for (int value : values) {
    tags |= value;
  }
  return tags;
}

现在判断是否打开了站内提醒

5 & 1 == 0000 0101 & 0000 0001 == 1

/**
 *  是否包含状态位
 *  tags: 已有状态位
 *  value: 需要判断的状态值
 */
public static boolean hasTag(int tags, int value) {
  return (tags & value) == value;
}

现在要关闭站内提醒

5 ^ 1 == 0000 0101 ^ 0000 0001 == 4

/**
  * 移除状态位
  * tags: 已有状态位
  * value: 需要移除的状态值
  */
public static int delTag(int tags, int value) {
  if ((tags & value) != value) return tags;
  return tags ^ value;
}

测试:

public static void main(String[] args) {
    int tag = addTag(0, 1, 4);
    System.out.println(tag); // 5
    System.out.println(hasTag(tag, 1)); // true
    System.out.println(hasTag(tag, 2)); // false
    System.out.println(hasTag(tag, 4)); // true
    tag = delTag(tag, 4);
    System.out.println(tag); // 1
    System.out.println(hasTag(tag, 4)); // false
}

使用优化

在日常开发中,这些状态可以通过枚举值进行封装起来,方便使用。

@Getter
public enum NotifyTypeEnum {
    IN_MAIL(1, "站内信提醒", 1),
    EMAIL(2, "邮件提醒", 2),
    SMS(3, "短信提醒", 4),
    ;

    // 枚举值
    private Integer code;
    // 枚举描述
    private String desc;
    // 状态位
    private Integer tag;

    NotifyTypeEnum(Integer code, String desc, Integer tag) {
        this.code = code;
        this.desc = desc;
        this.tag = tag;
    }

    public boolean hasTag(int tags) {
        return (tags & this.tag) == tag;
    }

    public static void main(String[] args) {
        int tags = 5;
        System.out.println(NotifyTypeEnum.IN_MAIL.hasTag(tags)); // true
        System.out.println(NotifyTypeEnum.EMAIL.hasTag(tags)); // false
        System.out.println(NotifyTypeEnum.SMS.hasTag(tags)); // true
    }
}

参考

标签:实战,0000,tags,二进制,System,value,int,tag,标位
来源: https://www.cnblogs.com/vcmq/p/12813026.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有