zoukankan      html  css  js  c++  java
  • java位运算符生产环境应用分析

    在实际应用场景中 特别是 1,2,4,8,16 这种2的整数次幂的数字,因为具有非常典型的特点

    • 首先是 1、2、4 这几位数了,因为他们的特点就是二进制只有一个为 1 的位,其他位都是 0,并同其他数位 1 的位不冲突
    •  所以我们的其中一个场景 比如用户需要一个字段他是多个字段值组合而成的,比如这样一个场景 有一个员工技能表 有技能内容

    •  一个员工可能对应多个技能那我们通过

    • public static Integer addSkill(Integer originalSkill, Integer addSkill) {
          if (originalSkill == null) {
              return addSkill;
          }
          return originalSkill ^ addSkill;
      }

      如上代码 把多个技能相加 得到一个最终结果

    • 之后要展示时
    •  通过迭代 拿到每个子内容

    首先来回顾一下位运算,什么是位运算呢?

    位运算就是直接对整数在内存中的二进制位进行操作。

    在 Java 语言中,位运算有如下这些:

    • 左移(<<)。

    • 右移(>>)。

    • 无符号右移(>>>)。

    • 与(&)。

    • 或(|)。

    • 非(~)。

    • 异或(^)。

    在本篇文章中,我们所需要用到的有如下几个(其他的后续文章再讲):

    • &(与运算):只有当两方都为 true 时,结果才是 true,否则为 false。

    • |(或运算):只要当一方为 true 时,结果就是 true,否则为 false。

    • ^(异或运算):只要两方不同,结果就是 true,否则为 false。

    以 true、false 为例:

    
    true & true  = true
    
    true & false = false
    
    
    
    true | false = true;
    
    false | false = false;
    
    
    
    true ^ true = false;
    
    true ^ false = true;
    
    复制代码

    以数字运算为例:

    
    6 & 4 = ?
    
    6 | 4  = ?
    
    6 ^ 4 = ?
    
    复制代码

    当以数字运算时,我们首先需要知道这些数字的二进制,假设 6 是 int 类型,那么其二进制如下:

    
    00000000 00000000 00000000 00000110
    
    复制代码

    在 Java 中,int 占了 4 个字节(Byte),一个字节呢又等于 8 个 Bit 位。所以 int 类型的二进制表现形式如上。

    在这里为方便讲解,直接取后 8 位:00000110。

    4 的二进制码如下:

    
    00000100
    
    复制代码

    在二进制码中,1 为 true,0 为 false,根据这个,我们再来看看 6 & 4 的运算过程:

    
        00000110
    
        00000100
    
        -----------
    
        00000100
    
    复制代码

    对每位的数进行运算后,结果为 4。

    再来看看 | 运算:

    
    6 | 4 = ?
    
    复制代码

    6 和 4 的二进制上面已经说了:

    
        00000110
    
        00000100
    
        -----------
    
        00000110
    
    
    复制代码

    可以发现最后的结果是 6。

    最后再来看看 ^ 运算:

    
    6 ^ 4 = ?
    
    复制代码
    
        00000110
    
        00000100
    
        -----------
    
        00000010
    
    复制代码

    结果是 2。

    应用

    通过上面的例子,我们已经回顾了 & 、 | 以及 ^ 运算。现在来将它应用到实际的应用中。

    假如我们现在要定义一个人的模型,这个人可能会包含有多种性格,比如说什么乐观型、内向型啦...

    要是想要知道他包含了哪种性格,那么我们该如何判断呢?

    可能在第一时间会想到:

    
    if(这个人是乐观性){
    
        ....
    
    }else if(这个人是内向型){
    
        ...
    
    }
    
    复制代码

    那么如果有很多种性格呢?一堆判断写起来真的是很要命..

    下面就来介绍一种更简单的方式。首先来定义一组数:

    
    public static final int STATUS_NORMAL     = 0;
    public static final int STATUS_OPTIMISTIC = 1;
    public static final int STATUS_OPEN       = 2;
    public static final int STATUS_CLOSE      = 4;
    复制代码

    把它们转换为二进制:

    
    0000 0000 0000 0000
    0000 0000 0000 0001
    0000 0000 0000 0010
    0000 0000 0000 0100
    复制代码

    发现其中二进制的规律没有?都是 2 的次幂,并且二进制都只有一个为 1 位,其他都是 0 !

    然后再来定义一个变量,用于存储状态(默认值是 0):

    
    private static int mStatus = STATUS_NORMAL;
    复制代码

    当我们要保存状态时,直接用 | 运算即可:

    
    mStatus |= STATUS_OPTIMISTIC;
    复制代码

    保存的运算过程如下:

    
        00000000
    
                        执行 | 运算(只要有 1 则为 1)
    
        00000001
    
        -----------
    
        00000001 = 1
    
    复制代码

    相当于就把这个 1 存储到 0 的二进制当中了。

    那么如果要判断 mStatus 中是否有某个状态呢?使用 & 运算:

    
    System.out.println((mStatus & STATUS_OPTIMISTIC) != 0);// true,代表有它
    复制代码

    计算过程如下:

    
        00000001
    
                       执行 & 运算(都为 1 才为 1)
    
        00000001
    
        -----------
    
        00000001 = 1
    
    复制代码

    再来判断一个不存在的状态 mStatus & STATUS_OPEN

    
    System.out.println((mStatus & STATUS_OPEN) != 0);// false,代表没有它
    复制代码

    计算过程如下:

    
        00000001
    
        00000010
    
        -----------
    
        00000000 = 0
    
    复制代码

    可以发现,因为 STATUS_OPEN 这个状态的二进制位,1 的位置处,mStatus 的二进制并没有对于的 1,而又因为其他位都是 0,导致全部归 0,计算出来的结果自然也就是 0 了。

    这也就是为什么定义状态的数字中,是 1、2、4 这几位数了,因为他们的特定就是二进制只有一个为 1 的位,其他位都是 0,并同其他数位 1 的位不冲突。

    如果换成其他的数,就会有问题了。比如说 3:

    
    mStatus |= 3
    
    复制代码

    计算过程:

    
        00000000
    
        00000011
    
        -----------
    
        00000011 = 3
    
    复制代码

    运算完毕,这时候 mStatus 中已经存储了 3 这个值了,我们再来判断下是否存在 2:

    
    System.out.println((mStatus & 2) != 0);// true,代表有它,但是其实是没有的
    复制代码
    
        00000011
    
        00000010
    
        -----------
    
        00000010 = 2
    
    复制代码

    结果是 true,但是其实我们只存储了 3 到 mStatus 中,结果肯定是错误的。

    所以我们在定义的时候,一定不要手滑定义错了数字。

    存储和判断已经说了,那么如何取出呢?这时候就要用到 ^ 运算了。

    假如现在 mStatus 中已经存储了 STATUS_OPTIMISTIC 状态了,要把它给取出来,这样写即可:

    
    mStatus ^= STATUS_OPTIMISTIC
    
    复制代码

    其中的运算过程:

    
        00000001
    
                        执行 ^ 运算,两边不相同,则为 true
    
        00000001
    
        -----------
    
        00000000
    
    复制代码

    可以看到状态又回到了最初没有存储 STATUS_OPTIMISTIC 状态的时候了。

    最后再来看一个取出的例子,这次是先存储两个状态,然后再取出其中一个:

    
    mStatus |= STATUS_OPTIMISTIC
    
    mStatus |= STATUS_OPEN
    
    复制代码

    存储完后,mStatus 的二进制为:

    
    00000011
    
    复制代码

    再来取出 STATUS_OPEN 这个状态:

    
    mStatus ^= STATUS_OPEN
    
    复制代码

    运算过程:

    
    00000011
    
    00000010
    
    -----------
    
    00000001
    
    复制代码

    mStatus 现在就只有 STATUS_OPTIMISTIC 的状态了。

    总结

    通过 |、^、& 运算,我们可以很方便快捷的对状态值进行操作。当然,位运算的应用不仅限于状态值,知道了其中的二进制运算原理后,还有更多的其他应用场景,等着你去发现。

    摘自
    https://juejin.im/post/5d4cf36651882575595c449a

  • 相关阅读:
    VBA值列选取与复制,赋值
    Processing的条件式
    VBA之四给程序自动加行号
    自上而下的语法分析
    Processing绘制四边形
    Processing的代码编写流程
    Processing编程语言简介
    follow集的求解
    Processing函数与循环
    在UBUNTU下用ruby求得网卡地址IP地址和用户名
  • 原文地址:https://www.cnblogs.com/zhangfengshi/p/12882505.html
Copyright © 2011-2022 走看看