00:00

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

OperatorNameRule per bit12 op 10
&AND1 if both bits are 18
|OR1 if at least one bit is 114
^XOR1 if the bits are different6
~NOT (unary)Flips every bit~12 = -13
BitwiseBasics.java
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)");
    }
}
Output
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

ABA & BA | BA ^ B~A
000001
010111
100110
111100

4. Shift Operators

OperatorNameWhat it does
<<Left shiftMoves bits left, filling with 0s. x << n multiplies by 2n (until overflow).
>>Signed right shiftMoves bits right, copying the sign bit. x >> n divides by 2n, rounding down.
>>>Unsigned right shiftMoves bits right, filling with 0s regardless of sign.
ShiftOperators.java
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)");
    }
}
Output
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 for long), so 1 << 32 is 1, not 0.
  • 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:

PermissionFlags.java
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));
    }
}
Output
start:          rw-
add execute:    rwx
remove write:   r-x
toggle read:    --x
can execute?    true
TaskCode
Set a flagflags |= FLAG
Clear a flagflags &= ~FLAG
Toggle a flagflags ^= 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

BitTricks.java
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));
    }
}
Output
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) == 1 tests for odd numbers.
  • n & (n - 1) clears the lowest set bit; if the result is 0, n is a power of two.
  • XOR swapping is a classic puzzle, but a temporary variable is clearer in real code.
  • Integer and Long provide ready-made helpers: bitCount, highestOneBit, numberOfTrailingZeros, reverse and toBinaryString.

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) and hash & (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