開發技巧:秀兒,如何才能一個字段表示八個狀態啊

1、驚現問題

💡 有一天,忽然來了一個需求,問小明提交了哪些課程的做業?java

🌱 A:語文 B:數學 C:英語 D:物理 E:化學 F:生物 G:歷史 H:地理 .....

  • 這麼多課程.....我要8個字段? 萬一還有課程呢?我還要再加字段?bash

  • 我確定不慌啊,我一個字段搞定。工具

2、解決之道

經過一個 int或者long 字段,來添加多個 標誌或者狀態. 一個int或者long字段,可以管理多個標記(狀態)值. 如此神奇的操做怎樣實現的呢? 答案就是經過位運算來實現.測試

  • 像這種,獨立狀態(標記)之間相互組合能夠產生新的狀態(標記),且每一個獨立狀態(標記)只有true或者false值的,咱們可使用位狀態的概念來管理這些狀態.spa

  • 它的核心思想就是將, int 數值看作是 二進制數位表示.若是有四個狀態就能夠像這樣 0000,用四位二進制表示,每個二進制位均可以表示一種狀態. 而後經過 位運算,來提取或添加標記位.四位對應的組合狀態有16個. 而咱們,只須要經過一個int變量就可以管理這些狀態.3d

  • 當參與的狀態(標記)越多時,若是使用單獨的標記變量,就須要生成越多的變量,而用位域,這種獨立狀態爲無論有多少個,均可以用一個變量表示.int類型最多存放32個獨立狀態.調試

  • 位操做基礎:code

java中提供的基礎位運算符有 與(&),或(|),非(~),異或(^),左移<<,右移(>>)無符號右移(>>>).cdn

除了位非(~)是一元操做符外,其它的都是二元操做符。對象

  • 下面只介紹本文中,使用到的位操做:

1.位與

A & B : A和B對應的二進制數位都爲1時,結果才爲1,其餘狀況爲0.

A     =  001101 // 13
B     =  100101 // 37
A & B =  000101 // 5
複製代碼

2.位或

A | B : A和B對應的二進制數位都爲0時,結果才爲0,其餘狀況爲1.

A     =  001101 // 13
B     =  100101 // 37
A | B =  101101 // 45
複製代碼

3.位非

~A : 將a的二進制表示每一位進行取反操做,0變1,1變0.至關於相反數 - 1

A     =  001101 // 13
~A    =  11111111111111111111111111110010 // int32位,補碼錶示,第一位爲符號位
// 根據上訴補碼轉原碼爲
//       10000000000000000000000000001110 // -14
複製代碼

4.左移操做

A << B:將A的二進制表示的每一位向左移B位, 左邊超出的位截掉,右邊不足的位補0。在取值範圍內,移動一位至關於乘2.

A     =  001101 // 13
A << 1 = 011010 // 26
複製代碼

3、實戰操做

/** * @author LiJing * @ClassName: BitStatusUtils * @Description: 位運算處理狀態的工具類 * @date 2019/9/21 * @time 10:38 */
public class BitStatusUtils {

    //A:語文 B:數學 C:英語 D:物理 E:化學 F:生物 G:歷史 H:地理 

    // 二進制表示 0001 沒有交任何做業
    public static final int NONE              = 1<<0;   //默認
    public static final int CHINESE           = NONE<<1;//語文
    public static final int MATH              = NONE<<2;//數學
    public static final int ENGLISH           = NONE<<3;//英語
    public static final int PHYSICS           = NONE<<4;//物理
    public static final int CHEMISTRY         = NONE<<5;//化學
    public static final int BIOLOGY           = NONE<<6;//生物
    public static final int HISTORY           = NONE<<7;//歷史
    public static final int GEOGRAPHY         = NONE<<8;//地理

    public static final int ALL =NONE|CHINESE|MATH|ENGLISH|PHYSICS|CHEMISTRY|BIOLOGY|HISTORY|GEOGRAPHY;

    /** * @param status 全部狀態值 * @param value 須要判斷狀態值 * @return 是否存在 */
    public static boolean hasStatus(long status, long value) {
        return (status & value) != 0;
    }

    /** * @param status 已有狀態值 * @param value 須要添加狀態值 * @return 新的狀態值 */
    public static long addStatus(long status, long value) {
        if (hasStatus(status, value)) {
            return status;
        }
        return (status | value);
    }

    /** * @param status 已有狀態值 * @param value 須要刪除狀態值 * @return 新的狀態值 */
    public static long removeStatus(long status, long value) {
        if (!hasStatus(status, value)) {
            return status;
        }
        return status ^ value;
    }
    
     /**是否交了含有所有狀態 * @param status * @return */
    public static boolean hasAllStatus(long status) {
        return (status & ALL) == ALL;
    }

    public static void main(String[] args) {

        long status = addStatus(NONE, CHINESE);
        System.out.println("小明交了語文做業:" + status);

        status = addStatus(status, PHYSICS);
        System.out.println("小明又交了物理做業:" + status);

        status = addStatus(status, HISTORY);
        System.out.println("小明還交了歷史做業:" + status);

        status = removeStatus(status, HISTORY);
        System.out.println("小明撤銷了歷史做業:" + status);

        System.out.println("小明是否交了語文做業:" + hasStatus(status, CHINESE));
        System.out.println("小明是否交了歷史做業:" + hasStatus(status, HISTORY));
        System.out.println("小明是否交了生物做業:" + hasStatus(status, BIOLOGY));
        System.out.println("小明是否交了所有做業:" + hasAllStatus(status));
    }
}
複製代碼

測試結果:

小明交了語文做業:3
小明又交了物理做業:19
小明還交了歷史做業:147
小明撤銷了歷史做業:19
小明是否交了語文做業:true
小明是否交了歷史做業:false
小明是否交了生物做業:false
小明是否交了所有做業:false
複製代碼

4、完美小結

  • 內存由字節組成.每一個字節由8位bit組成,每一個bit狀態只能是0或1.

  • 所謂位模式,無非就是變量所佔用內存的全部bit的狀態的序列

  • 運用場景:

    1. 訂單實體,咱們可能涉及到的狀態有,是否發貨,是否審覈,是否付款,是否接受等等.
    2. 棋牌遊戲用戶狀態
    3. 棋盤的位圖(棋盤模式)位置(域):上下左右 左上角 右上角 左下角 右下角 方位等待
    4. 用戶是否提交多項認證資料等
  • 優點:

    1. 佔用內存少
    2. 具備高效的拷貝、設值、比較運算等
    3. 位並行運算的可能
  • 不足:

    1. 難於調試
    2. 訪問單獨位的複雜性,易出錯
    3. 難於擴展
    4. 不符合面向對象的風格
    5. 不能處理全部的任務;須要大量的工做
  • 喜歡嗎?喜歡就別愣着啊 點贊啊~~ 感謝你們關注我...聽說點贊延年益壽哦。
相關文章
相關標籤/搜索