二进制的骚操作,省字段,省带宽,提效率…

  • 2019 年 12 月 20 日
  • 筆記

介绍

上一个礼拜和一个同事对接口,前端同事问我是不是接口文档写错了,一个订单的异常标签有多个,不应该返回一个数组吗?为啥只返回了一个数字。

因为这个接口是调用别微服务,所以我也很疑惑,找同事确认,他只回了我一句用位表示状态。我立马就懂了,因为Linux下的权限也是这么干的(Linux下的权限管理居然这么有意思),然后找到他们的代码确认了一番,果然和我想的一样,看看是怎么做的吧

其实很简单,就一个如下的枚举类

public enum EXTEND_FLAG_ENUM {        OVER_WEIGHT(1, "超重"),      OVER_CUBAGE(1 << 1, "超方"),      LATE(1 << 2, "晚点"),      SLOW(1 << 3, "缓行");        public int value;      public String name;        EXTEND_FLAG_ENUM(int value, String name) {          this.value = value;          this.name = name;      }        public static int addFlag(int org, EXTEND_FLAG_ENUM newFlag) {          return org | newFlag.value;      }        public static int removeFlag(int org, EXTEND_FLAG_ENUM oldFlag) {          return org & (~oldFlag.value);      }      public static boolean hasFlag(int org, EXTEND_FLAG_ENUM oldFlag) {          return (org & oldFlag.value) > 0;      }  }

用4个二进位为来表示订单的状态

二进制

代表状态

十进制

0001

超重

1

0011

超重,超方

3

1011

超重,超方,缓行

11

1111

超重,超方,晚点,缓行

15

简单解释一下与或非操作

与操作(有0出0,全1出1)

数字

二级制

A

1 0 1 0

B

1 1 0 0

A & B

1 0 0 0

或操作(有1出1;全0出0)

数字

二级制

A

1 0 1 0

B

1 1 0 0

A | B

1 1 1 0

非操作(有1出0;有0出1)

数字

二级制

A

1 0 1 0

~A

0 1 0 1

以下断言测试通过

@Test  public void showTest() {      // 订单的异常标签初始为0      int extendFlag = 0;      // 标记订单超重      extendFlag = EXTEND_FLAG_ENUM.addFlag(0, EXTEND_FLAG_ENUM.OVER_WEIGHT);      assertTrue(EXTEND_FLAG_ENUM.hasFlag(extendFlag, EXTEND_FLAG_ENUM.OVER_WEIGHT));      // 标记订单超方      extendFlag = EXTEND_FLAG_ENUM.addFlag(extendFlag, EXTEND_FLAG_ENUM.OVER_CUBAGE);      // 订单确实超重和超方了      assertTrue(EXTEND_FLAG_ENUM.hasFlag(extendFlag, EXTEND_FLAG_ENUM.OVER_WEIGHT));      assertTrue(EXTEND_FLAG_ENUM.hasFlag(extendFlag, EXTEND_FLAG_ENUM.OVER_CUBAGE));  }

前端拿到一个整数就能解析出相应的状态

@Test  public void showTest2() {      // [1]      System.out.println(getExtendFlag(1));      // [1, 2, 8]      System.out.println(getExtendFlag(11));      // [1, 2, 4, 8]      System.out.println(getExtendFlag(15));  }    public List<Integer> getExtendFlag(int num) {      List<Integer> numList = new ArrayList<>();      int temp = 1;      while (temp < 16) {          if ((num & temp) >= 1) {              numList.add(temp);          }          temp = temp << 1;      }      return numList;  }

你看,一个数字同时记录多种状态,节省数据库字段和带宽,程序可扩展性也变强了,增加新的状态只需要增加一个枚举属性即可。

二进制的其他骚操作

普通操作

骚操作

n * 2

n << 1

n / 2

n >> 1

n % 1 == 1

n & 1 == 1

没别的,位操作就是快

判断一个数是否是2的指数,我原来面试的时候被问到过

bool isPowerOfTwo(int n) {      if (n <= 0) return false;      return (n & (n - 1)) == 0;  }

2的指数二进制的形式一定是1000,2的指数-1的二进制的形式一定是111,所以与操作一定是0

二进制的骚操作还有很多,但是并不常用,这里只列举了一些常用的