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

  • 相关阅读:
    Eclipse 导入项目乱码问题(中文乱码)
    sql中视图视图的作用
    Java基础-super关键字与this关键字
    Android LayoutInflater.inflate(int resource, ViewGroup root, boolean attachToRoot)的参数理解
    Android View和ViewGroup
    工厂方法模式(java 设计模式)
    设计模式(java) 单例模式 单例类
    eclipse乱码解决方法
    No resource found that matches the given name 'Theme.AppCompat.Light 的完美解决方案
    【转】使用 Eclipse 调试 Java 程序的 10 个技巧
  • 原文地址:https://www.cnblogs.com/zhangfengshi/p/12882505.html
Copyright © 2011-2022 走看看