将位打包在一起
让我们看一下这段代码。
public static final int MULTI = 1 << 1;
public static final int SINGLE = 1 << 2;
public static final int READ_ONLY = 1 << 3;
“<<”运算符表示向左移动位。“<<”运算符后面的数字告诉我们要移动多少位。
因此,另一种编写代码的方式是。
public static final int MULTI = 2;
public static final int SINGLE = 4;
public static final int READ_ONLY = 8;
通过以这种方式定义标志,这些值可以被或(“加”)在一起并保存在一个字节或一个整数中。
SWT.MULTI | SWT.SINGLE
这就是说将两个值的位组合在一起。但是,这是什么意思?
在这种情况下,由于我们将值定义为单个位,因此与添加值相同。
MULTI = 2
SINGLE = 4
因此,状态值为 6 (2 + 4)。
现在请记住,我们没有添加。因为我们使用的是位,所以效果就像我们在添加一样。
拆包位
您发布的第二段代码基本上采用了我们提出的 6,然后将其拆分为 2 和 4。它的工作原理是检查每一位,一次一个,看看它是否存在。
让我们拿一条线,看看它在做什么。
if ((style & int1) != 0) style = (style & ~mask) | int1;
int1
表示样式位之一。为了便于讨论,假设它是 MULTI,值为 2。
第一部分(if 条件)测试是否在样式整数中设置了该位。
第二部分有点棘手。(一点,明白了。非常双关语。)
mask 的值在代码中给出。
int mask = int0 | int1 | int2 | int3 | int4 | int5;
这只是所有状态值 OR'd 在一起。从我们最初的 MULTI、SINGLE 和 READ_ONLY 示例中,我们得到了 x'0E' 或 14 的掩码。在接下来的讨论中,我将使用十六进制。
存在状态位
现在,回到我们正在谈论的那一行。
if ((style & int1) != 0) style = (style & ~mask) | int1;
style & int1
是一个 AND 操作。这意味着必须在style
和中设置该位int1
。 Style
是我们之前设置时的 x'06' (2 + 4)。 int1
是 x'02'。当你 AND x'06' 和 x'02' 时,你会得到 x'02',这就是 if 的值true
。
~mask
将 x'0E' 转换为 x'F1'。换句话说,所有位都从 0 翻转到 1,从 1 翻转到 0。
style & ~mask
是一个 AND 操作。当你 AND x'06' 和 x'F1' 时,你得到 x'00'。换句话说,没有一个位匹配。
前面我们说过int1是MULTI,取值为2或者x'02'。现在我们做一个 OR 操作,我们之前解释过。对 x'00' 和 x'02' 进行 ORing 得到 x'02',这是我们想要提取的 MULTI 值。
状态位不存在
另一种选择(当状态位不存在时)会导致略有不同的结果。我们没有设置 READ_ONLY,所以让我们来计算一下。
READ_ONLY 是 x'08'。样式为 x'06' 当您将这些值与 if 中的值一起使用时
if ((style & int1) != 0) style = (style & ~mask) | int1;
你得到 x'00',这导致 if 的值为false
。
理由
将多个状态值放入一个字节或字的最初原因是为了节省内存。这在 40 年前计算机内存有限的时候很重要。现在,这样做是为了方便传递状态。不是将 7 或 15 个不同的状态指示器从一种方法传递到另一种方法,而是传递一个状态指示器。
如您所见,折衷是需要一些代码来提取状态位,以便您可以使用它们。