二进制的骚操作,省字段,省带宽,提效率…
- 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
二进制的骚操作还有很多,但是并不常用,这里只列举了一些常用的