java.awt.Event 类中的一些int变量是按位设置的。如下所示:
/**
* This flag indicates that the Shift key was down when the event
* occurred.
*/
public static final int SHIFT_MASK = 1 << 0;
/**
* This flag indicates that the Control key was down when the event
* occurred.
*/
public static final int CTRL_MASK = 1 << 1;
/**
* This flag indicates that the Meta key was down when the event
* occurred. For mouse events, this flag indicates that the right
* button was pressed or released.
*/
public static final int META_MASK = 1 << 2;
/**
* This flag indicates that the Alt key was down when
* the event occurred. For mouse events, this flag indicates that the
* middle mouse button was pressed or released.
*/
public static final int ALT_MASK = 1 << 3;
为什么不使用增加1的整数直接编码。
public static final int SHIFT_MASK = 1;
public static final int CTRL_MASK = 2;
public static final int META_MASK = 3;
public static final int ALT_MASK = 4;
有历史原因还是程序员的编码习惯?
也许你可以使用 a&amp; b 比较两个变量,但 a == b 也可以。
它是否适合某些情况?如果是这样,你能举个例子吗?
希望得到你的回答,谢谢。
答案 0 :(得分:2)
我不知道这里是否需要另一个答案,但我认为没有真正解释过你为什么要这样做。
至于这种语法的原因,他们将它作为一个位域实现。 bitfield是一种将一堆布尔值存储在内存中的单个位置的方法。这曾经很常见,仍然很有用。具有60个布尔值的对象(除了本质上不好的设计之外)将需要60x4个字节来存储,位打包可以将所有60个布尔值放入单个长度(4位备用)。如果你有100万个这个对象的实例,那么打包你的位意味着需要8MB存储空间(100万个8字节长)和需要240MB存储空间(100万x 60个布尔值,每个占用4个字节)之间的区别。
这些天你几乎不应该使用位域 - 我们通常没有内存问题,并且有更好的结构可用。当你开始将数据组合到位域时,操作实际上变得非常慢(这就是为什么java使用整个32位int来存储每个布尔值而不是为你打包它们。)
顺便说一下,了解打包数据结构仍然很重要,因为互联网上的数据经常被打包,有人必须编写代码来解压缩它(不得不写一次mp4头解码器,一塌糊涂)
另一个有趣的问题,为什么说“1&lt;&lt;&lt; 0&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; 4&gt这是一件非常好的事情。布局时,这些常量非常易读 - 第一个位置有一位,第五个位置有一位。你只需看一眼就知道该位的确切位置。指定该位的第二个最简单的方法是十六进制,如果你很好,你就知道0x0400是0000010000000000.最糟糕的是十进制,因为除非你是一个学者,或者只是在计算机上工作很多你不会知道知道哪个位位置是1024或32768,并且设置2位的常数将是非常困难的。
以符合您意图的方式进行编码,并且在人们认为最自然的语言中很容易理解,这是一种神奇的习惯。这些天我经常使用它的代码如下:
public final long SHORT_DELAY = 8000
public final long LONG_DELAY = 85808000
那是8000秒,8000天?此外,当数字变得很长时,很难解析。
我更喜欢:
public final long sec= 1000
public final long min=sec * 60
public final long hour=min * 60
public final long SHORT_DELAY = 8 * sec
public final long LONG_DELAY = 2 * hour + 23 * min + 8 * sec
这只是编码的一个问题,读者会清楚这一点,你引用的代码就是一个很好的例子,所以如果这就是“编码风格”,那就意味着它太棒了,绝对是相关的。
答案 1 :(得分:1)
如果你看一下它的二进制形式,那就更有意义了:
1 << 0 : 00000001
1 << 1 : 00000010
1 << 2 : 00000100
1 << 3 : 00001000
这种位图通常允许您同时传递多于1个值(作为某种修饰符)。
因此,您可能会看到类似的内容:
// modifiers is a single int
if ((modifiers & SHIFT_MASK) != 0) {
// shift pressed
}
if ((modifiers & CTRL_MASK) != 0) {
// ctrl pressed
}....
(如果您将它们定义为1,2,3,4,则无法执行此操作)
你可以认为它正在传递一组位。这样的掩码用于确定特定位是&#34; ON&#34;还是打开/关闭特定位而不影响其他位
答案 2 :(得分:1)
为什么这样?正如在其他答案中指出的那样,值是2的幂,因此你设置了一点。假设你想测试一系列条件。
然后你可以组合比特,例如,
SOME_COMBO_CONDITION = SHIFT_MASK | ALT_MASK
然后通过测试是否通过执行
来设置两个位来测试该条件current_condition&amp; SOME_COMBO_CONDITION
使用整数代码,您必须使用更复杂的条件进行测试。
答案 3 :(得分:1)
示例很简单,假设控制和 shift键被按下。使用上面的代码,这会使bitstring像这样:
...11
为了使它具体化,让我们使用一个8位字符串,如下所示:
0111 0011
这表示可能已经压下了几个键,但也许您只对移位和控制键感兴趣。如果您想知道两者何时按下shift和控制键,您可以创建一个新的组合:
CTRL_AND_SHIFT_MASK = SHIFT_MASK | CTR_MASK;
然后你可以做一个按位并确定返回的位串是否两者控制和移位键被按下:
final boolean isCtrlAndShift = (CTRL_AND_SHIFT_MASK & val) == CTRL_AND_SHIFT_MASK;
通过按位进行,如果CTRL和SHIFT的两个位都不是两个 1,那么'和'将导致两个位中的一个变为0.所有其他位将是0无论如何(因为它们在CTRL_AND_SHIFT_MASK
中为0)。因此,如果and
使用您的价值val
,那么它应该回馈您的CTRL_AND_SHIFT_MASK
,否则只有一个或两个都不会被压抑。
答案 4 :(得分:0)
因为这些值没有增加一个。它们是2的幂,用于使用按位或 - 或 - 或 - 二进制 - 等等进行测试。
int[] arr = { 1 << 0, 1 << 1, 1 << 2, 1 << 3 };
System.out.println(Arrays.toString(arr));
输出
[1, 2, 4, 8]
这是编写2 n 的一种方式,其中n
是<<
右侧的数字。