單個變量保存多個狀態

問題

在 Java 中,如何使用一個 byte 類型的變量保存多個 boolean 類型的值?

場景

請選擇喜愛的球類運動(多選):

□ 足球 □ 籃球 □ 乒乓球
□ 臺球 □ 排球 □ 羽毛球

在如上所描述的場景中,如何使用一個 byte 類型的變量來保存各項是否選中?

回答

常規思路是定義 6 個 boolean 類型的變量,每個變量保存一項的狀態, 選中為 true , 否則為 false

boolean footballIsChecked = false;
...
boolean badmintonIsChecked = false;

在 Java 中,byte 類型的數據使用 8 位進行保存,每一位的值可能是 01。理論上來講,byte 類型存儲空間的每一位可以表示一個 boolean 類型的值,1 表示 true0 表示 false

byte sportCheckedState;
sportCheckedState = 0b0000_0000; //都沒選中
sportCheckedState = 0b0000_0001; //選中了足球
sportCheckedState = 0b0000_0010; //選中了籃球

因此,我們的需要解決問題變成了如何將 byte 類型某一位存儲空間的值設置為 01, 如何讀取某一位的值。

設置 byte 類型某一位的存儲空間的值

如何將某一位的值設置為 0 呢?

0 & 0 = 0
0 & 1 = 0

答:該位和 0 進行 & 運算。

如何將某一位的值設置為 1 呢?

1 | 0 = 1
1 | 1 = 1

答:該位和 1 進行 | 運算。

既然是設置某一位的值,就應該不影響其他位的值。

執行 & 運算時,如何讓運算結果和運算數相等?

1 & 0 = 0
1 & 1 = 1

答:當另外一個運算數為 1 時,運算結果和此運算數相同。

執行 | 運算時,如何讓運算結果和運算數相等?

0 | 0 = 0
0 | 1 = 1

答:當另外一個運算數為 0 時,運算結果和此運算數相同。

綜上,設置某一位為 0 時,進行 & 運算,輔助運算數(另外一個參與運算的數)應該符合這樣的規則:目標位為0, 其他位為 1。 例如設置最后一位,輔助運算數為 1111_1110

  1 0 1 0
& 1 1 1 0 //輔助運算數
 ----------
  1 0 1 0 //運算結果的前 3 位不變,最后一位設置為 0
  1 0 1 1
& 1 1 1 0 //輔助運算數
 ----------
  1 0 1 0 //運算結果的前 3 位不變,最后一位設置為 0

設置某一位為1 時,進行 | 運算,輔助運算數應該符合這樣的規則:目標位為 1, 其它位為 0。例如設置最后一位,輔助運算數為 0000_0001

  1 0 1 0
| 0 0 0 1 //輔助運算數
 ----------
  1 0 1 1 //運算結果的前 3 位不變,最后一位設置為 1
  1 0 1 1
| 0 0 0 1 //輔助運算數
 ----------
  1 0 1 1 //運算結果的前 3 位不變,最后一位設置為 1

讀取 byte 類型某一位的存儲空間的值

1 進行 & 時,運算結果和另外一個運算數相同。

1 & 0 = 0
1 & 1 = 1

0 進行 & 時,運算結果為0

0 & 0 = 0
0 & 1 = 0

為了方便,我們希望 & 運算結果的其他位為 0,根據 0000_0000的運算結果可以推算出目標位的值為 0;根據目標位為 1,其它位的值為 0 的運算結果可以推算出目標位的值為 1

所以,構造出的輔助運算數應該符合這樣的規則:目標位的值為 1,其他位的值為 0。例如,倒數第二位應該選取的輔助運算數為 0000_0010

  1 0 1 0
& 0 0 1 0 //輔助運算數
 ----------
  0 0 1 0 //運算結果的 1、2、4  位置為 0,第 3 為值為 1 ,即運算數第 3 位值為 1
  1 0 0 0
& 0 0 1 0 //輔助運算數
 ----------
  0 0 0 0 //運算結果的 1、2、4  位置為 0,第 3 為值為 0 ,即運算數第 3 位值為 0

據此,我們可以得出結論:運算結果每一位的值都是 0 時,目標位的值為 0;運算結果存在值不為 0 的位時,目標位的值為 1

示例

  // 每個狀態用一位表示,1 選中, 0 未選中
  private static final byte CHECKED_FOOTBALL = 0b0000_0001;

  private byte state = STATE_VALUE_DEFAULT;

  public void setFootballCheckedState(boolean isChecked) {
    if (isChecked) {
      state = (byte) (state | CHECKED_FOOTBALL);
    } else {
      state = (byte) (state & ~CHECKED_FOOTBALL);
    }
  }

  public boolean footballIsChecked() {
    return (state & CHECKED_FOOTBALL) == CHECKED_FOOTBALL;
  }

參考資料

happut : 單一字段存儲多狀態思路

代碼

XuMeng-0/android-study

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容