首先来回顾一下位运算,什么是位运算呢?bash
位运算就是直接对整数在内存中的二进制位进行操做。spa
在 Java 语言中,位运算有以下这些:code
左移(<<)。内存
右移(>>)。it
无符号右移(>>>)。class
与(&)。变量
或(|)。原理
非(~)。二进制
异或(^)。总结
在本篇文章中,咱们所须要用到的有以下几个(其余的后续文章再讲):
&(与运算):只有当两方都为 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 了。
这也就是为何定义状态的数字中,是 一、二、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
的状态了。
经过 |、^、& 运算,咱们能够很方便快捷的对状态值进行操做。固然,位运算的应用不只限于状态值,知道了其中的二进制运算原理后,还有更多的其余应用场景,等着你去发现。