Bitwise and Bit Shift Operators in Java
Bitwise operators work on the individual binary digits of a value rather than on the number as a whole. Java provides four logical bitwise operators — & (AND), | (OR), ^ (XOR), and ~ (NOT) — plus three bit shift operators: <<, >>, and >>>. These operators apply to long, int, short, byte and char.
1. Bitwise Operators: AND, OR, XOR, NOT
The following table lists the bitwise operators available in Java:
| Operator | Description |
|---|---|
~ | Bitwise unary NOT operation (NOT, bitwise complement) |
& | Bitwise binary AND operation (AND, bitwise conjunction) |
| | Bitwise binary OR operation (OR, bitwise disjunction) |
^ | Bitwise binary exclusive OR operation (XOR) |
Truth table for the four operations:
| A | B | A | B | A & B | A ^ B | ~A |
|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 1 |
| 1 | 0 | 1 | 0 | 1 | 0 |
| 0 | 1 | 1 | 0 | 1 | 1 |
| 1 | 1 | 1 | 1 | 0 | 0 |
1.1. Bitwise OR (OR, |)
A result bit produced by the OR operator is 1 if the corresponding bit is 1 in at least one of the operands:
00101010 42
| 00001111 15
--------------
00101111 47 1.2. Bitwise AND (AND, &)
A result bit produced by the AND operator, &, is 1 only if the corresponding bits in both operands are also 1. In every other case the result bit is 0:
00101010 42
& 00001111 15
--------------
00001010 10 1.3. Bitwise Exclusive OR (XOR, ^)
A result bit produced by the XOR operator, ^, is 1 if the corresponding bit is 1 in exactly one of the operands. In every other case the result bit is 0:
00101010 42
^ 00001111 15
--------------
00100101 37 1.4. Bitwise NOT (NOT, ~)
The unary NOT operator, ~, also called the bitwise complement, inverts every bit of its operand:
~ 00101010 42
--------------
11010101 Let's see how bitwise operations work in a program. The following example also shows Integer.toBinaryString(), which returns the binary representation of a decimal value:
public class BitwiseExample1 {
public static void main(String[] args) {
int a = 3;
int b = 6;
int c = a | b;
int d = a & b;
int e = a ^ b;
int f = ~b;
System.out.println("a = " + Integer.toBinaryString(a));
System.out.println("b = " + Integer.toBinaryString(b));
System.out.println("a | b = " + Integer.toBinaryString(c));
System.out.println("a & b = " + Integer.toBinaryString(d));
System.out.println("a ^ b = " + Integer.toBinaryString(e));
System.out.println("~ b = " + Integer.toBinaryString(f));
}
} Program output (toBinaryString() does not print leading zeros):
a = 11
b = 110
a | b = 111
a & b = 10
a ^ b = 101
~ b = 11111111111111111111111111111001 2. Bit Shift Operators: >>, >>> and <<
Bit shift operators move all binary digits of a value a given number of positions:
| Operator | Name | What happens to the bits |
|---|---|---|
<< | Left shift | Bits move left; zeros are filled in on the right |
>> | Right shift (arithmetic) | Bits move right; the sign bit is copied on the left — the sign is preserved |
>>> | Unsigned right shift (zero-fill) | Bits move right; zeros are filled in on the left regardless of sign |
General form:
value << amount Examples:
34<<3, 56>>2, 78>>>1 To understand how a shift works, it helps to look at binary numbers directly:
0001<<1 = 0010
0100>>1 = 0010 The difference between >> and >>> shows up when shifting negative numbers. The >> operator propagates the sign (leftmost) bit to the right, while >>> fills the vacated positions with zeros. For positive numbers the result of both operations is the same:
int i = 192;
i 00000000 00000000 00000000 11000000 (192)
i<<1 00000000 00000000 00000001 10000000 (384)
i>>1 00000000 00000000 00000000 01100000 (96)
i>>>1 00000000 00000000 00000000 01100000 (96)
int i = -192; (two's complement representation)
i 11111111 11111111 11111111 01000000 (-192)
i<<1 11111111 11111111 11111110 10000000 (-384)
i>>1 11111111 11111111 11111111 10100000 (-96)
i>>>1 01111111 11111111 11111111 10100000 (2147483552) Note
For a negative number, >>> clears the sign bit, so the result is always a large positive number: -192 >>> 1 yields 2147483552, not "minus 96 unsigned". If you need to divide a negative number by a power of two while keeping its sign, use >>.
Types byte and short are promoted to int when the expression is evaluated. The following example shows what this leads to:
public class BitwiseExample2 {
public static void main(String[] args) {
byte a = 64; //0100 0000
byte b;
int i = a << 2; // 1 0000 0000
b = (byte) (a << 2); //0000 0000
System.out.println("a = " + a);
System.out.println("i = " + i);
System.out.println("b = " + b);
}
} Program output:
a = 64
i = 256
b = 0 Important
The result of a << 2 has type int, even though a is declared as byte or short. The value 256 fits in an int, but casting it back to byte discards the high-order bits — leaving 0. Assigning the result to a byte without a cast won't compile: byte b = a << 2; fails.
3. Bitwise Assignment Operators
Each bitwise operator has a corresponding compound assignment operator:
| Operator | Description | Equivalent to |
|---|---|---|
&= | Bitwise AND assignment | x &= y → x = x & y |
|= | Bitwise OR assignment | x |= y → x = x | y |
^= | Bitwise XOR assignment | x ^= y → x = x ^ y |
>>= | Right shift assignment | x >>= n → x = x >> n |
>>>= | Unsigned right shift assignment | x >>>= n → x = x >>> n |
<<= | Left shift assignment | x <<= n → x = x << n |
There is one nuance: compound assignment performs an implicit cast to the type of the variable. That's why byte b = 64; b <<= 2; compiles (and, per the rule above, produces 0), while b = b << 2; is a compile error.
4. Practical Uses of Bitwise Operators
Bitwise operators have a fairly wide range of practical applications. Let's look at a few cases.
4.1. Checking Whether a Number Is Even
The expression x & 1 checks whether a number is even: an even number has its lowest bit equal to 0, an odd number has it equal to 1. The parentheses in (x & 1) == 0 are required — because & has lower precedence than ==, without them the expression would be parsed as x & (1 == 0) and would not compile.
4.2. Multiplying and Dividing a Number by Two
x<<1– multiplies by 2;x>>1– divides by two, discarding any remainder.
Each additional shift position is one more multiplication or division by 2. For negative numbers, x>>1 rounds down rather than toward zero, so the result can differ from x/2: -5 >> 1 equals -3, while -5/2 equals -2.
4.3. Encrypting a Number
Applying the XOR operator twice to the same bit pattern restores its original value. This can be used to encrypt data sent over a network:
C = A ^ B
A = C ^ B Suppose you need to send a number, 560 — a bank card PIN — in a message. If an attacker intercepts it, they'll learn the PIN and could use it. To prevent this, agree on some number in advance — a mask — with the recipient. Before sending, encrypt the PIN with the bitwise XOR operation: message ^ mask — and send the result. Even if an attacker intercepts the message, they won't know how to decrypt it. The recipient recovers the PIN using the shared mask: codedMessage ^ mask.
The following code illustrates this:
public class BitwiseExample3 {
public static void main(String[] args) {
int message = 560;
int mask = 67;
int codedMessage = message ^ mask;
int receivedMessage = codedMessage ^ mask;
System.out.println("message = " + message);
System.out.println("message = " + Integer.toBinaryString(message));
System.out.println("codedMessage = " + codedMessage);
System.out.println("codedMessage = " + Integer.toBinaryString(codedMessage));
System.out.println("receivedMessage = " + receivedMessage);
System.out.println("receivedMessage = " + Integer.toBinaryString(receivedMessage));
}
} Program output — after XOR-ing again with the same mask, the recipient sees the original 560:
message = 560
message = 1000110000
codedMessage = 627
codedMessage = 1001110011
receivedMessage = 560
receivedMessage = 1000110000 4.4. Applying a Bit Mask
A mask lets you extract only specific bits from a sequence. For example, take the mask 00100100. It extracts from a sequence only the bits that are set in it — in this case, the 3rd and 6th bit. To do this, simply perform a bitwise AND between the mask and the chosen number:
001010101
& 000100100
--------------
000000100 Frequently Asked Questions
Where are bitwise operators used in real code?
Most often for bit flags and masks: a single int field can store up to 32 settings, a flag is checked with &, set with |, and cleared with & ~. Bitwise operators also show up in network protocols and binary file formats, in color handling (extracting RGB channels), in hash functions, and in cryptography. Even the standard library uses them: HashMap computes its bucket index as (n - 1) & hash.
What is the difference between >> and >>> in Java?
The >> operator is an arithmetic shift: the sign bit is copied in on the left, so the sign of the number is preserved. The >>> operator is an unsigned shift: zeros are always filled in on the left. For positive numbers the results are identical, but for negative numbers they differ sharply: -192 >> 1 gives -96, while -192 >>> 1 gives 2147483552, because the sign bit is cleared and the number becomes a large positive value.
Why does ~x equal -x - 1?
Because of the two's complement representation Java uses to store integers: the negative of a number is obtained by inverting all its bits and adding one, that is, -x == ~x + 1. Rearranging gives ~x == -x - 1. Easy to verify: ~42 equals -43, and ~0 equals -1 (all 32 bits become ones).
How do you check whether a number is even with a bitwise operator?
With the expression (x & 1) == 0 — it is true for even numbers. The mask 1 keeps only the lowest bit, which is 0 for even numbers and 1 for odd ones. This also works correctly for negative numbers, thanks to two's complement. The parentheses around x & 1 are required: & has lower precedence than ==, and without them the expression won't compile.
Comments