java.util.regex.Pattern
and operation set in java.nio.SelectionKey
. Therefore, knowing how to use bitwise operators allow us to manipulate the bit field and make use of the API efficiently.Bitwise OR |
Only return 0 when both operands are 0, otherwise return 1. This characteristic is commonly used to turn on a particular bit (to be specific, set 1 to a bit) in a bit field.Existing bit field | 1 | 0 | 1 | 0 |
| | ||||
Bit Mask | 1 | 1 | 0 | 0 |
= | ||||
Outcome | 1 | 1 | 1 | 0 |
The outcome will be the new bit field that override existing bit field. As you can see in the new bit field's state, the second bit in the highlighted column has been turned on.
Bitwise XOR ^
Return 0 when both operands are same, otherwise return 1. This characteristic is an extension of bitwise OR, where it can be used to turn on a bit. But it will turn off the existing bit if the bit is currently on.Existing bit field | 1 | 0 | 1 | 0 |
^ | ||||
Bit Mask | 1 | 1 | 0 | 0 |
= | ||||
Outcome | 0 | 1 | 1 | 0 |
Again, the outcome will be the new bit field that override existing bit field. And the new bit field's state shows that first bit has been turned off and the second bit has been turned on.
Bitwise AND &
Only return 1 when both operands are 1, otherwise return 0. This characteristic is commonly used to check the state of a bit.Existing bit field | 1 | 0 | 1 | 0 |
& | ||||
Bit Mask | 1 | 1 | 0 | 0 |
= | ||||
Outcome | 1 | 0 | 0 | 0 |
The outcome, in this case, is not meant for overriding the existing bit field. Instead, it reveals the status of the interested bit based on the bitmask. In the example above, outcome shows that the first bit in bit field is currently on.
Bitwise NOT ~
To invert a bit. From 1 to 0, or 0 to 1. It commonly used together with bitwise AND operator to un-set/turn off a bit. ~1 = 0 ~0 = 1Using Bitwise Operators in Java
The characteristic of each bitwise operators is clear now. Below is the examples of using bitwise operators in Java. First of all, we need a set of numeric constants. There are a few ways to declare them.Assigning Decimal Value
public static final byte RED = 1; //0000 0001 public static final byte ORANGE = 2; //0000 0010 public static final byte YELLOW = 4; //0000 0100 public static final byte GREEN = 8; //0000 1000 public static final byte BLUE = 16; //0001 0000 public static final byte INDIGO = 32; //0010 0000 public static final byte VIOLET = 64; //0100 0000
Using Bit Shift Operator
public static final byte RED = 2 >> 1; //0000 0001 public static final byte ORANGE = 2 << 0; //0000 0010 public static final byte YELLOW = 2 << 1; //0000 0100 public static final byte GREEN = 2 << 2; //0000 1000 public static final byte BLUE = 2 << 3; //0001 0000 public static final byte INDIGO = 2 << 4; //0010 0000 public static final byte VIOLET = 2 << 5; //0100 0000
Assigning Binary Value
public static final byte RED = 0b00000001; public static final byte ORANGE = 0b00000010; public static final byte YELLOW = 0b00000100; public static final byte GREEN = 0b00001000; public static final byte BLUE = 0b00010000; public static final byte INDIGO = 0b00100000; public static final byte VIOLET = 0b01000000;
All 3 set of constants above are giving the same value. It is up to you to choose which one giving you the best picture. One more important point to take away is that the max amount of constant variables is depend on the max positive size of the data type. I am using
byte
for the example above. 1 byte equals to 8 bits and the max positive size of byte
is 127. Therefore, we could only have 7 constant variables. In short, it is up to you to choose the data type that's fit your needs.Below is the code example in using bitwise operators to manipulate bitField.
byte bitField = 0; /************** * Bitwise OR **************/ // Turn on ORANGE bit in bitField. bitField |= ORANGE; // bitField becomes 00000010. We got ORANGE now. System.out.println(Integer.toBinaryString(bitField)); // Turn on more bits in bitField. bitField |= BLUE | VIOLET; // bitField becomes 01010010. We got VIOLET, BLUE and ORANGE now. System.out.println(Integer.toBinaryString(bitField)); /************** * Bitwise XOR **************/ // Turn on YELLOW bit in bitField. bitField ^= YELLOW; // bitField becomes 01010110. We got VIOLET, BLUE, YELLOW, and ORANGE now. System.out.println(Integer.toBinaryString(bitField)); // Turn off BLUE bit in bitField. bitField ^= BLUE; // bitField becomes 01000110. We got VIOLET, YELLOW, and ORANGE now. System.out.println(Integer.toBinaryString(bitField)); /************** * Bitwise AND **************/ // Check if the desired bit flag is on. boolean isExist = (bitField & ORANGE) == ORANGE ? true : false; // isExist = true. ORANGE is exist in the bitField. System.out.println(isExist); /*********************** * Bitwise NOT with AND ***********************/ // Turn off VIOLET bit in bitField. bitField &= ~VIOLET; // bitField becomes 00000110. We got YELLOW, and ORANGE now. System.out.println(Integer.toBinaryString(bitField));
Disadvantages of using Bit Field
Although bit field is a useful technique, but it come along with disadvantages as below.- Hard to interpret bit field by reading numbers.
- No type safe as it using constant as bit masks.
- No easy way to iterate through the bit field.
java.util.EnumSet
class which could effectively replace bit field technique and avoids from all bit field advantages mentioned above. We could use EnumSet
to do the same things in the Colour bit field example above. In addition, EnumSet
provides a rich set of java.util.Set
functionalities, type safe, and its performance is comparable to the bit field as it internally represented in with a single long
.In conclusion, familiar with bit field technique so we could use the old Java API (those still require bit field as a parameter) properly. But moving forward, make use of
EnumSet
in our new methods to gain all the benefits given by EnumSet
.References:
http://www.vipan.com/htdocs/bitwisehelp.html
Book: Effective Java Second Edition by Joshua Bloch
No comments:
Post a Comment