我想知道如何屏蔽一个值,以便我可以设置配置。假设我有常量 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);
}
}