位操作-在Java中使用位操作符屏蔽选项



我想知道如何屏蔽一个值,以便我可以设置配置。假设我有常量 Options.A = 0, Options.B = 1等等。

builder.setOption( Option.A & Option.C ); // Or should I use '|' operator?

这意味着

Option.A    Option.B    Option.C    Option.D
    1           0           1           0

由于1010是数字10的二进制,这意味着builder.option = 10;,但在实际实现中,我会有一个switch的情况,将其进行比较:

// inside builder.someFunction();
switch(this.option) {
    case Option.A & Option.C:

注意:请纠正我,如果这不是你如何使用按位运算符来屏蔽值,我读了很多,不太理解它,所以如果这是错误的,我可能需要一个像switch-case这样的例子。

PS:我以Android框架中的一行代码为例,如下所示:

view.gravity = Gravity.TOP | Gravity.LEFT;

这是我想实现的一个类似的行为

首先,理论:

(1)我们忽略数据类型,假设你有4个选项:

Option.A    Option.B    Option.C    Option.D

那么您需要使用一个4位宽度的变量来表示它们。假设的选择。A是最高(最左边)位,也是选项。D是最低的(最右边)。那么这个变量看起来是:

Option.A    Option.B    Option.C    Option.D
  bit3        bit2        bit1        bit0 

取值范围为0000~1111,代表2^4 = 16种不同的组合。

(2)对于位操作,你应该首先定义每个选项的掩码:

var Mask.A = 1000;
var Mask.B = 0100;
var Mask.C = 0010;
var Mask.D = 0001;

<1>如果您想要表示具有Option的值。B和Option.C,你可以使用OR操作:

var v_B_and_C = Mask.B | Mask.C = 0100 | 0010 = 0110;

<2>如果要检查某个值是否包含Option。B,使用AND,然后比较结果:

var some_v = 1101;
var result = some_v & Mask.B = 1101 & 0100 = 0100;
if(result != 0000) {// Contains Option.B! }
else {// ==0000. Not contains Option.B! }

<3>如果你想反转一个值,你可以使用NOT/XOR:

var some_v = 0011;
var reversion_v = ~some_v = ~0011 = 1100;
// you can also use XOR(^) between a value and an all-1 constant
var reversion_v = some_v ^ 1111 = 0011 ^ 1111 = 1100;

<4>如果您想知道两个值之间的差异,可以使用XOR:

var v_1 = 1100, v_2 = 0110;
var diff = v_1 ^ v_2 = 1100 ^ 0110 = 1010 // Means bit3, bit1 are different!

<5>对于其他用途,ref: Bitwise Operation

第二,在Java中练习:

(1)你需要弄清楚的第一件事是你需要代表多少Options(bits) ?因为不同的数据类型有不同的宽度(表示不同的范围):

  • short: 2Bytes, 16bit,表示2^16 = 65536个组合。
  • int: 4Bytes, 32bit,表示2^32 = 4294967296种组合。
  • long: 8Bytes, 64bit,表示2^64 = 18446744073709551616组合。

如果你需要超过64个选项,你可能需要使用array(int[]/long[]),或者一个方便的类:java.util.BitSet

(2)如果您希望通过数组实现自己,请使用按位操作关键字(&,|,^,~,<<<,>>>)。有一个以二进制格式打印int的提示:

int i = 0x80000000;
System.out.println(Integer.toBinaryString(i));
// Print: 10000000000000000000000000000000

(3)我建议使用java.util.BitSet类,除非你有必须自己实现的理由。例子:

import java.util.BitSet;
public class Main {
   public static void main(String[] args) {
      // Create a BitSet object, which can store 128 Options.
      BitSet bs = new BitSet(128);
      bs.set(0);// equal to bs.set(0,true), set bit0 to 1.
      bs.set(64,true); // Set bit64
      // Returns the long array used in BitSet
      long[] longs = bs.toLongArray();
      System.out.println(longs.length);  // 2
      System.out.println(longs[0]); // 1
      System.out.println(longs[1]); // 1
      System.out.println(longs[0] ==longs[1]);  // true
   }
}

其他用法参见java文档

我从来没有实现过这个,但是我想到了这样的事情:

对于第一个问题,是的,您需要使用|(而不是&)来正确地累积选项

如果你要在一个变量中积累选项,那么为了检查哪些选项是ON的,我会对使用:

for(int i=0;i<32;i++){
    if(i&options){//check if i-th option is ON
        option_function(i);
    }
}

和option_function()内部进行切换。

void option_function(int i){
    switch(i) {
        case Option.A:
            ....
}

}

为什么不创建一个更容易阅读并使用标准API的类呢?

public class Permissions { 
    final BitSet permissions;
    public Permissions() {
        permissions = new BitSet();
    }
    public void setPermission(int p) {
        permissions.set(p);
    }
}

最新更新