Eugene
Eugene

Reputation: 11075

When should I use this kind of int variables?

Some int variables in java.awt.Event class is set by bitwise. Like below:

/**
 * 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;

Why not coding directly using integers incremented by 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;

Is there any historical reason or it's just programmer's coding habit?

Maybe you can use a & b to compare two variables but a == b works too.

Does it suit for some situations?If so , could you please give me an example?

Hope to get answer from you, thanks.

Upvotes: 1

Views: 111

Answers (5)

Adrian Shum
Adrian Shum

Reputation: 40036

If you look at its binary form, it makes more sense:

1 << 0 :  00000001
1 << 1 :  00000010
1 << 2 :  00000100
1 << 3 :  00001000

Such kind of bit map usually allow you to pass more than 1 value at the same time (as some kind of modifier).

Therefore, you may see something like:

// modifiers is a single int
if ((modifiers & SHIFT_MASK) != 0) {
    // shift pressed
}
if ((modifiers & CTRL_MASK) != 0) {
    // ctrl pressed
}....

(which you cannot do if you defined them as 1,2,3,4)

You can think of it being passing a set of bits. Such mask to determine whether a specific bit is "ON", or to turn on/off a specific bit without affecting other bits

Upvotes: 1

Jared
Jared

Reputation: 940

The example is easy, let's say that the control and shift key are depressed. Using the above, this would make the bitstring something like this:

...11

To make it concrete, let's use an 8 bit string, say something like this:

0111 0011

This would represent that several keys may have been depressed, but perhaps you are only interested in the shift and control keys. If you want to know when both the shift and control key are depressed you can create a new combination:

CTRL_AND_SHIFT_MASK = SHIFT_MASK | CTR_MASK;

Then you can do a bitwise and to determine whether or not the returned bit string has both the control and shift keys depressed:

final boolean isCtrlAndShift = (CTRL_AND_SHIFT_MASK & val) == CTRL_AND_SHIFT_MASK;

By doing a bitwise and, if the two bits for CTRL and SHIFT aren't both 1, then and'ing will result in one of the two bits becoming 0. All other bits will be 0 regardless (since they are 0 in CTRL_AND_SHIFT_MASK). So if you and it with your value val then it should give back your CTRL_AND_SHIFT_MASK otherwise only one or neither is depressed.

Upvotes: 1

Bill K
Bill K

Reputation: 62769

I don't know if another answer is needed here but I don't think any really explained why you'd want to do this.

As for the reason for this syntax, they are implementing it as a bitfield. A bitfield is a way to store a bunch of booleans in a single place in memory. This used to be quite common and still can be useful. An object that has 60 booleans (aside from being an inherently bad design) would take 60x4 bytes to store, bit-packing could put all 60 booleans into a single long (with 4 bits to spare). If you had 1 million instances of this object then packing your bits means the difference between needing 8MB of storage (1 million 8-byte longs) and needing 240MB of storage (1 million x 60 booleans each taking 4 bytes).

These days you should almost never use bitfields--we don't usually have an issue with memory and there are better structures available. When you start combining data into bitfields operations actually get significantly slower (which is why java uses an entire 32bit int to store each boolean instead of packing them for you).

By the way, it is still important to know about packed data structures because data over the internet often gets packed and someone has to write code to unpack it (Had to write an mp4 header decoder once, what a mess)

Another interesting question, why say "1 << 0" and "1 << 4" instead of just saying "1" and "16". This is a really good thing to look at. When laid out those constants are extremely readable--one bit in the first position, one bit in the fifth position. You know exactly what position the bit is in by just glancing at it. The second easiest way to specify the bit is hex, if you are good you'd know right of that 0x0400 was 0000010000000000. The worst would be decimal because unless you're a savant or just work with computers a lot you wouldn't know know which bit position was 1024 or 32768, and a constant with 2 bits set would be insanely difficult.

Coding in a way that matches your intention and is easily understandable in a language another human would find most natural is a FANTASTIC habit. Where I usually use it these days is in code like:

public final long SHORT_DELAY = 8000
public final long LONG_DELAY = 85808000

Is that 8000 seconds, 8000 days? Also when the number gets really long it's hard to parse.

I prefer:

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

This is just a matter of coding in a way that will be clear to your reader, and the code you referenced was a fantastic example of this, so if that's the "Coding style" you meant it is fantastic and is absolutely still relevant.

Upvotes: 3

paisanco
paisanco

Reputation: 4164

Why do this? As pointed out in the other answers, the values are powers of two and you are thereby setting a bit. Suppose you wanted to test for a combination of conditions.

You could then combine bits like for example,

SOME_COMBO_CONDITION = SHIFT_MASK | ALT_MASK

and then test for that condition by testing if both bits are set by doing

current_condition & SOME_COMBO_CONDITION

Using integer codes you'd have to test using a more complex conditional.

Upvotes: 1

Elliott Frisch
Elliott Frisch

Reputation: 201447

Because those values aren't increasing by one. They are powers of two and used for testing with bitwise-or, exclusive-or, binary-and, etc.

int[] arr = { 1 << 0, 1 << 1, 1 << 2, 1 << 3 };
System.out.println(Arrays.toString(arr));

Output is

[1, 2, 4, 8]

It's a way of writing 2n where n is the number to the right of the <<.

Upvotes: 0

Related Questions