Bitwise and Shift Operators in Java – Explained with Examples
Computers store every integer as a row of bits (0s and 1s). Bitwise operators work directly on those bits, and shift operators move them left or right. They are used for flags and permissions, hashing, compression, graphics, network protocols and fast arithmetic tricks.
This tutorial explains Java's four bitwise operators (&, |, ^, ~) and three shift operators (<<, >>, >>>) with binary diagrams and practical examples.
1. A Quick Look at Binary
Each bit position represents a power of two. The number 12 is 8 + 4, so its 8-bit pattern is 00001100; 10 is 8 + 2, or 00001010. A Java int has 32 bits, and negative numbers are stored in two's complement: the highest bit is the sign bit, and -n equals ~n + 1.
2. The Bitwise Operators
| Operator | Name | Rule per bit | 12 op 10 |
|---|---|---|---|
& | AND | 1 if both bits are 1 | 8 |
| | OR | 1 if at least one bit is 1 | 14 |
^ | XOR | 1 if the bits are different | 6 |
~ | NOT (unary) | Flips every bit | ~12 = -13 |
public class BitwiseBasics {
static String bits(int n) {
return String.format("%8s", Integer.toBinaryString(n & 0xFF)).replace(' ', '0');
}
public static void main(String[] args) {
int a = 12; // 00001100
int b = 10; // 00001010
System.out.println("a = " + bits(a) + " (" + a + ")");
System.out.println("b = " + bits(b) + " (" + b + ")");
System.out.println("a & b = " + bits(a & b) + " (" + (a & b) + ") AND: 1 if both bits are 1");
System.out.println("a | b = " + bits(a | b) + " (" + (a | b) + ") OR: 1 if either bit is 1");
System.out.println("a ^ b = " + bits(a ^ b) + " (" + (a ^ b) + ") XOR: 1 if bits differ");
System.out.println("~a = " + (~a) + " NOT: every bit flipped (two's complement)");
}
}
a = 00001100 (12) b = 00001010 (10) a & b = 00001000 (8) AND: 1 if both bits are 1 a | b = 00001110 (14) OR: 1 if either bit is 1 a ^ b = 00000110 (6) XOR: 1 if bits differ ~a = -13 NOT: every bit flipped (two's complement)
Why is ~12 equal to -13? Flipping all 32 bits of 12 sets the sign bit, and in two's complement ~n always equals -n - 1.
3. Truth Table
| A | B | A & B | A | B | A ^ B | ~A |
|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 1 |
| 0 | 1 | 0 | 1 | 1 | 1 |
| 1 | 0 | 0 | 1 | 1 | 0 |
| 1 | 1 | 1 | 1 | 0 | 0 |
4. Shift Operators
| Operator | Name | What it does |
|---|---|---|
<< | Left shift | Moves bits left, filling with 0s. x << n multiplies by 2n (until overflow). |
>> | Signed right shift | Moves bits right, copying the sign bit. x >> n divides by 2n, rounding down. |
>>> | Unsigned right shift | Moves bits right, filling with 0s regardless of sign. |
public class ShiftOperators {
public static void main(String[] args) {
int n = 20;
System.out.println("20 << 2 = " + (n << 2) + " (multiply by 4)");
System.out.println("20 >> 2 = " + (n >> 2) + " (divide by 4)");
System.out.println("20 >>> 2 = " + (n >>> 2));
int neg = -20;
System.out.println("-20 >> 2 = " + (neg >> 2) + " (sign bit copied: stays negative)");
System.out.println("-20 >>> 2 = " + (neg >>> 2) + " (zeros shifted in)");
System.out.println("1 << 10 = " + (1 << 10));
System.out.println("1 << 32 = " + (1 << 32) + " (shift distance is taken mod 32 for int)");
}
}
20 << 2 = 80 (multiply by 4) 20 >> 2 = 5 (divide by 4) 20 >>> 2 = 5 -20 >> 2 = -5 (sign bit copied: stays negative) -20 >>> 2 = 1073741819 (zeros shifted in) 1 << 10 = 1024 1 << 32 = 1 (shift distance is taken mod 32 for int)
- For positive numbers,
>>and>>>give the same result. - For negative numbers,
>>>produces a large positive number because a 0 enters the sign position. - Only the low 5 bits of the shift distance are used for
int(6 bits forlong), so1 << 32is1, not0. - There is no
<<<operator; a left shift always fills with zeros.
5. Practical Use: Flags and Permissions
Each bit can represent an on/off option, so one integer can store many flags. This is how file permissions, feature switches and many protocols work:
public class PermissionFlags {
static final int READ = 1; // 001
static final int WRITE = 2; // 010
static final int EXECUTE = 4; // 100
static String describe(int p) {
return ((p & READ) != 0 ? "r" : "-") + ((p & WRITE) != 0 ? "w" : "-") + ((p & EXECUTE) != 0 ? "x" : "-");
}
public static void main(String[] args) {
int perms = READ | WRITE; // set two flags
System.out.println("start: " + describe(perms));
perms |= EXECUTE; // add a flag
System.out.println("add execute: " + describe(perms));
perms &= ~WRITE; // remove a flag
System.out.println("remove write: " + describe(perms));
perms ^= READ; // toggle a flag
System.out.println("toggle read: " + describe(perms));
System.out.println("can execute? " + ((perms & EXECUTE) != 0));
}
}
start: rw- add execute: rwx remove write: r-x toggle read: --x can execute? true
| Task | Code |
|---|---|
| Set a flag | flags |= FLAG |
| Clear a flag | flags &= ~FLAG |
| Toggle a flag | flags ^= FLAG |
| Test a flag | (flags & FLAG) != 0 |
For readable application code, an EnumSet gives the same compact storage with type safety.
6. Useful Bit Tricks
public class BitTricks {
public static void main(String[] args) {
// Even/odd: the lowest bit is 1 for odd numbers
System.out.println("37 is odd? " + ((37 & 1) == 1));
// Power of two: exactly one bit set
for (int n : new int[] {64, 96}) {
System.out.println(n + " power of two? " + (n > 0 && (n & (n - 1)) == 0));
}
// Swap two variables without a temporary
int x = 7, y = 3;
x ^= y; y ^= x; x ^= y;
System.out.println("swapped: x=" + x + ", y=" + y);
// Count set bits and find the highest one
System.out.println("bits set in 255: " + Integer.bitCount(255));
System.out.println("highest one bit of 100: " + Integer.highestOneBit(100));
// Toggle letter case (works for ASCII letters)
System.out.println("'a' ^ 32 = " + (char) ('a' ^ 32) + ", 'Q' ^ 32 = " + (char) ('Q' ^ 32));
}
}
37 is odd? true 64 power of two? true 96 power of two? false swapped: x=3, y=7 bits set in 255: 8 highest one bit of 100: 64 'a' ^ 32 = A, 'Q' ^ 32 = q
(n & 1) == 1tests for odd numbers.n & (n - 1)clears the lowest set bit; if the result is 0,nis a power of two.- XOR swapping is a classic puzzle, but a temporary variable is clearer in real code.
IntegerandLongprovide ready-made helpers:bitCount,highestOneBit,numberOfTrailingZeros,reverseandtoBinaryString.
7. Bitwise Operators with Booleans
&, | and ^ also work on boolean values as logical operators that do not short-circuit: both sides are always evaluated. a ^ b on booleans means "exactly one is true". Prefer && and || for conditions unless you need both sides to run.
8. Precedence Pitfall
Bitwise operators have lower precedence than ==. Always use parentheses when testing bits: (flags & READ) != 0. Without them, flags & READ != 0 is parsed as flags & (READ != 0) and does not compile for int.
9. Where Bitwise Operations Are Used
- HashMap uses
h ^ (h >>> 16)andhash & (n - 1)to choose buckets. - Colours: extracting red, green and blue from a packed RGB integer with shifts and masks.
- Networking: IP address and subnet mask calculations.
- Compression, cryptography and checksums.
- Competitive programming: subsets with bitmasks.
10. Summary
&,|,^and~combine or flip individual bits.<<shifts left (×2n),>>shifts right keeping the sign,>>>shifts right filling with zeros.- Negative numbers use two's complement, so
~n == -n - 1. - Bit flags pack many on/off options into one integer.
- Use parentheses: bitwise operators bind more weakly than comparisons.
Related Tutorials
Frequently Asked Questions (FAQ)
Q1. What are bitwise operators in Java?
Operators that work on the individual bits of integer values: & (AND), | (OR), ^ (XOR) and ~ (NOT). Java also has the shift operators <<, >> and >>>.
Q2. What is the difference between & and &&?
&& is a logical AND for booleans that short-circuits. & is a bitwise AND for integers, and a non-short-circuit logical AND for booleans.
Q3. What does the XOR operator do?
^ sets a bit to 1 when the two input bits differ and to 0 when they are the same. Applying the same XOR twice restores the original value, which is used in toggling and simple ciphers.
Q4. Why is ~5 equal to -6?
~ flips all 32 bits, including the sign bit. In two's complement, flipping all bits of n gives -n - 1, so ~5 is -6.
Q5. What is the difference between >> and >>>?
>> copies the sign bit into the empty positions, so negative numbers stay negative. >>> always fills with zeros, so negative numbers become large positive numbers.
Q6. Is there a <<< operator in Java?
No. Left shifts always fill with zeros, so there is no need for a separate unsigned left shift.
Q7. Is left shift the same as multiplying by 2?
Each left shift by one doubles the value, as long as no significant bits are shifted out. When bits overflow past the sign position, the result can become negative or wrong.
Q8. Why does 1 << 32 equal 1?
For int, Java uses only the lowest 5 bits of the shift distance, so 32 becomes 0. For long, the lowest 6 bits are used. Use 1L << 32 to shift a long.
Q9. Can bitwise operators be used on booleans?
Yes, &, | and ^ work on booleans and always evaluate both operands. ~ does not work on booleans; use !.
Q10. Can bitwise operators be used on double or float?
No, only on integer types (byte, short, int, long, char) and booleans. To inspect a double's bits, use Double.doubleToLongBits().
Q11. How do I check whether a number is a power of two?
Use n > 0 && (n & (n - 1)) == 0. A power of two has exactly one bit set, and subtracting 1 clears it while setting all lower bits.
Q12. How do I print a number in binary?
Use Integer.toBinaryString(n) or Long.toBinaryString(n). Pad with String.format("%8s", ...).replace(' ', '0') for a fixed width.
Q13. How do I write binary literals?
Prefix the digits with 0b, for example int mask = 0b1010_1010;. Underscores improve readability.
Q14. What is a bitmask?
An integer whose bits mark which positions you want to read, set or clear. Combining a value with a mask using &, | or ^ isolates or changes those bits.
Q15. What is two's complement?
The way Java stores negative integers: the highest bit is the sign, and -n is formed by flipping all bits of n and adding one. It lets the same addition circuit work for positive and negative numbers.
Q16. Why do bitwise comparisons need parentheses?
Because == and != have higher precedence than &, ^ and |. Write (flags & MASK) != 0.
Q17. How do I swap two numbers using XOR?
a ^= b; b ^= a; a ^= b; swaps a and b without a temporary variable. It fails if both refer to the same array element, and a temporary variable is clearer in real code.
Q18. Are bitwise operations faster than arithmetic?
They are very cheap, but modern JIT compilers already turn multiplications and divisions by constants into shifts when that is faster. Use bitwise operators when they express your intent, not as a manual optimisation.
Q19. Where are bitwise operators used in the JDK?
In HashMap bucket selection, BitSet, EnumSet, character encoding, cryptography and many low-level utilities in Integer and Long.
Q20. What is the result type of bitwise operations on bytes?
An int, because byte, short and char operands are promoted to int. Cast the result back or use compound assignment such as b &= 0x0F.