首先來回顧一下位運算,什麼是位運算呢?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
的狀態了。
經過 |、^、& 運算,咱們能夠很方便快捷的對狀態值進行操做。固然,位運算的應用不只限於狀態值,知道了其中的二進制運算原理後,還有更多的其餘應用場景,等着你去發現。