为什么我们要在两个数字之间使用按位运算符?

Why would we use bitwise operators between 2 numbers?

鉴于以下信息,我不明白为什么您会想要使用 & 运算符计算例如 2 个十六进制整数。我理解下面解释的反转模式,我可以自己计算它,但是很难推断为什么(从我在互联网上看到的帖子)。什么是真实世界的场景,可以让我在这里有洞察力?

  0xff00 & 0xf0f0 is 0xf000
  0xff00 ^ 0xf0f0 is 0x0ff0
  0xff00 | 0xf0f0 is 0xfff0
For &, the result value is the bitwise AND of the operand values.
For ^, the result value is the bitwise exclusive OR of the operand values.
For |, the result value is the bitwise inclusive OR of the operand values.

在我自己的脑海里,我目前是这样想的:

if ( 65280 & 61680 )  // evaluates to 61440, not boolean?

这些运算符用于很多事情,但如今在高级语言中,它们最常与标志一起使用。它是 C 等低级语言的遗留物,其中内存分配和释放并不总是微不足道的,并且是在硬件资源稀缺的时候开发的。

假设某些操作有 3 个可能的标志,它们可以以任何给定的组合提供。提供标志的一种快速、简单且有效的方法是将每个标志分配给整数中的一个位。

public static final int FLAG_1 = 1;       // 00000001
public static final int FLAG_2 = 1 << 1;  // 00000010
public static final int FLAG_3 = 1 << 2;  // 00000100

然后要发送多个标志,我可以使用按位或“|”操作员。

someFunc(FLAG_1 | FLAG_3).

要读取传递的标志,我可以使用按位 & 运算符。

public void someFunc(int flags) {
    if ((flags & FLAG_1) == FLAG_1 /*Or (flags & FLAG_1) != 0 */) { 
      // Passed in flag 1.
    }
}

还有其他方法可以做到这一点,但这种方法非常有效,易于阅读,并且会导致堆上的对象分配为零。如果您想到其他方法可以在 Java 中完成此操作,比方说使用 enums/ints 的数组或集合,或者将每个标志作为单独的方法参数,那么很明显为什么要改用这种模式.

对于 if 语句中的一个非常基本的示例:

if ( (65280 & 1) == 0 ){
  // 65280 is even!
}
  • x & 10 如果 x 是偶数
  • x & 11 如果 x 是奇数

我认为如果你需要实现一个 boolean 的小数组,将它表示为 intlong 可能是个好主意,每个位代表一个数组元素:

  • 如果这些数组的数量很大,那么内存使用是一个问题;或
  • 如果您正在进行大量计算。

在这种情况下,您将使用移位运算符和 &|&=|=^= 进行测试,清除、设置或翻转数组的元素。 (另请注意,这可以并行用于数组的多个元素。)

这种情况很少见。为了可读性,最好使用常规 arrayArrayList。但是,这两个用例我都至少出现过一次。一个是使用强力回溯算法编写数独求解器;我不记得细节了,但我想我用了一个 int 的 9 位来表示行、列或正方形中的单元格是否被占用。如果我没记错的话,我的一些代码同时测试了多个单元格,我可以用一个 & 运算符来完成。由于通过回溯求解可能涉及大量的组合,我相信使用这种机制可以显着缩短 运行ning 时间。另一个案例涉及 table 个项目,这些项目保留有关项目是否具有某些属性的信息。属性的数量比较少(10到20之间),但是物品的数量可以运行上千万。 Set 本来是表示属性集的自然选择,但由于我需要保留大量 HashSet,内存是一个问题。

除非内存或时间有很大差异,否则我不会推荐这个。它带有 "trickiness" 的味道,我更喜欢表达您要完成的目标的直接代码。