什麼?你還不會用位運算來操做狀態?

回顧

首先來回顧一下位運算,什麼是位運算呢?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 的狀態了。

總結

經過 |、^、& 運算,咱們能夠很方便快捷的對狀態值進行操做。固然,位運算的應用不只限於狀態值,知道了其中的二進制運算原理後,還有更多的其餘應用場景,等着你去發現。

相關文章
相關標籤/搜索