As in many programming languages, Java offers a possibility for bit manipulation with bit operators. While the official documentation is kind of sparse, this article will give you more information about individual operators.
We can divide bit manipulating operators into two categories categorized by the kind of operation operators do. We have bitwise operators such as AND, OR, XOR and bitwise complement; and shift operators such as Signed right shift, Unsigned right shift and Unsigned left shift operators. Let’s take a closer look at individual operators with real-life examples.
Bitwise operators
Bitwise operators are used to perform individual bits manipulation. However, we can also use them with integral types such as char, short, int, etc.
Bitwise operator AND – &
AND operator is binary operator, denoted by ‘&’ character in Java. It returns bit result of AND operation on input variables.
Let’s take a look on AND table and explain the OR bit operator on example below:
A | B | A & B |
---|---|---|
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
A = 3 = 0011 [Binary]
B = 5 = 0101 [Binary]
Bitwise AND Operation of 3 and 5
0011 &
0101
________
0001 = 1 [Decimal]
& assignment trick
& can be in Java also combined with assignment operator to provide shorthand assignment e.g.:
a = a&b
a &= b;
Bitwise operator OR – |
OR operator is binary operator, denoted by ‘|’ character in Java. It returns bit result of OR operation on input variables.
Let’s take a look on OR table and explain the OR bit operator on example below:
A | B | A | B |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
A = 3 = 0011 [Binary]
B = 5 = 0101 [Binary]
Bitwise OR Operation of 3 and 5
0011 |
0101
________
0111 = 7 [Decimal]
Bitwise operator XOR – ^
XOR operator is binary operator, denoted by ‘^’ character in Java. It returns bit result of XOR operation on input variables.
Let’s take a look on XOR table and explain the OR bit operator on example below:
A | B | A ^ B |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
A = 3 = 0011 [Binary]
B = 5 = 0101 [Binary]
Bitwise XOR Operation of 3 and 5
0011 ^
0101
________
0110 = 6 [Decimal]
Bitwise complement – ~
This is unary operator, denoted by ‘~’ character in Java. It means it returns one’s complement representation of the input value. It means flipping bits on the opposite value where 1 is 0 and 0 is 1.
Let’s take a look on XOR table and explain the OR bit operator on example below:
A = 3 = 0011 [Binary]
Bitwise OR Operation of 3 and 5
~0011
________
1100 = 12 [Decimal]
Shift operators
Shift operators are used to shift the bits for a number of positions to the left or right. Due to bits movement, shifting bits multiply or divide the number by two, respectively.
Generally, shift operators can be used when we have to multiply or divide a number by two.
Signed right shift operator – >>
Signed right operator is denoted by ‘>>’ characters in Java. The signed right operator shifts the bits for the number of positions to the right and fills the blank bit positions with 0 as a result.
The leftmost bit depends on the sign of the initial number. With signed right shift we preserve the sign bit.
Similarly, shifting bits right affects number as if it would be divided by the power of two.
5 => 0 0101>>2 = 1 = 0 0001
-10 => 1 0110>>2 = -3 = 1111 1111 1111 1111 1111 1111 1111 1101
Unsigned right shift operator – >>>
Unsigned right operator is denoted by ‘>>>’ characters in Java. The unsigned right operator shifts the bits for the number of positions to the right and fills the blank bit positions with 0s.
The leftmost bit is set to 0. Difference between signed and unsigned right shift operator is that unsigned-shift operator (>>>) will insert 0 while signed operator (>>) will extend the sign bit. With unsigned right shift we do not preserve the sign bit.
5 => 0 0101>>>2 = 1 = 0 0001
// Similar to 5/(2^2)
8 => 0 1000>>>2 = 2 = 0 0010
// Similar to 8/(2^2)
-10 => 1 0110>>>2 = 1073741821 = 11 1111 1111 1111 1111 1111 1111 1101 = 0011 1111 1111 1111 1111 1111 1111 1101
// !!! Remember unsigned right shift operator for negative numbers - first 2 bits become 0 (and do not display in binary string)
Signed left shift operator – <<
Signed left operator is denoted by ‘<<<' characters in Java. The signed left operator shifts the bits for the number of positions to the left and fills the blank bit positions with 0s.
The leftmost bit depends on the sign of the initial number. With signed left shift we preserve the sign bit.
Similarly, shifting bits left affects the number as if it would be multiplied by the power of two.
5 => 0 0101<<2 = 20 = 10100
// Similar to 5*(2^2)
-10 => 1 0110<<2 = -40 = 1111 1111 1111 1111 1111 1111 1101 1000
// Similar to -10*(2^2)
Unsigned left shift operator - <<<
Unlike unsigned light shift, there is no "<<<" operator in Java. The logical (<<) and arithmetic left-shift (<<<) operations are identical.
Example code
public class Test {
public static void main(String []args) {
int a = 3;
int b = 5;
int c = -7;
int d = -10;
// For testing of bitwise and assigning operators use
// Integer.toBinaryString();
// Bitwise AND
// 0 0011 & 0 0101 = 0 0001 = 1
System.out.println("A & B = " + (a & b));
// 1 0111 & 1 1010 = 1 0000 = -16 = 1111 1111 1111 1111 1111 1111 1111 0000
System.out.println("C & D = " + (c & d));
// Bitwise OR
// 0 0011 | 0 0101 = 0 0111 = 7
System.out.println("A | B = " + (a | b));
// 1 0111 | 1 1010 = 1 1111 = -1 = 1111 1111 1111 1111 1111 1111 1111 1111
System.out.println("C | D = " + (c | d));
// Bitwise XOR
// 3 => 0 0011 ^ 0 0101 = 0 0110 = 6
System.out.println("A ^ B = " + (a ^ b));
// -7 => 1 0111 ^ 1 1010 = 0 1111 = 15
System.out.println("C ^ D = " + (c ^ d));
// Bitwise complement
// ~0 0011 = -4 = 1111 1111 1111 1111 1111 1111 1111 1100
System.out.println("~A = " + ~a);
// 1 0111 = 6 = 110
// will give 2's complement of 1010 = -6
System.out.println("~C = " + ~c);
// Signed right shift operator
// 5 => 0 0101>>2 = 1 = 0 0001
System.out.println("B>>2 = " + (b >> 2));
// -10 => 1 0110>>2 = -3 = 1111 1111 1111 1111 1111 1111 1111 1101
System.out.println("D>>2 = " + (d >> 2));
// Unsigned right shift operator
// 5 => 0 0101>>>2 = 1 = 0 0001
System.out.println("B>>>2 = " + (b >>> 2));
// -10 => 1 0110>>>2 = 1073741821 = 11 1111 1111 1111 1111 1111 1111 1101
System.out.println("D>>>2 = " + d >>> 2);
// !!! Important observation for negative numbers - first 2 bits become 0
// (and do not display in binary string)
// 5 => 0 0101<<2 = 20 = 10100
// Similar to 5*(2^2)
System.out.println("C<<2 = " + (b << 2));
// -10 => 1 0110<<2 = -40 = 1111 1111 1111 1111 1111 1111 1101 1000
// Similar to -10*(2^2)
System.out.println("D<<2 = " + (d << 2));
}
}
Note: Just to help with some bit transformation, here is a bit integer number transformation table to binary 4-bit and 8-bit representation.
Decadical | 16 | 255 |
---|---|---|
0 | 0000 | 00000000 |
1 | 0001 | 00000001 |
2 | 0010 | 00000010 |
3 | 0011 | 00000011 |
4 | 0100 | 000000100 |
5 | 0101 | 00000101 |
6 | 0110 | 00000110 |
7 | 0111 | 00000111 |
8 | 1000 | 00001000 |
9 | 1001 | 00001001 |
10 | 1010 | 00001010 |
11 | 1011 | 00001011 |
12 | 1100 | 00001100 |
13 | 1101 | 00001101 |
14 | 1110 | 00001110 |
15 | 1111 | 00001111 |
16 | ---- | 00010000 |
... | ... | ... |
254 | ---- | 11111110 |
255 | ---- | 11111111 |
Thank you!!