单个变量保存多个状态

2022-11-23  本文已影响0人  栩檬

问题

在 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

上一篇 下一篇

猜你喜欢

热点阅读