Bitwise Operators in Java

Master Java bitwise operators: AND, OR, XOR, NOT, and shift operators for manipulating individual bits, flags, and masks in low-level programming.

published: reading time: 13 min read author: Geek Workbench

Bitwise Operators in Java

Bitwise operators manipulate individual bits in integer values. They are essential for low-level programming, flag management, cryptography, and performance-critical operations.

Introduction

Bitwise operators manipulate individual bits within integer values — & (AND), | (OR), ^ (XOR), ~ (NOT), << (left shift), >> (signed right shift), and >>> (unsigned right shift). They are the operators of choice for low-level programming: flag management, cryptographic operations, network protocol implementation, and performance-critical numeric algorithms. Most application-level Java code rarely touches these operators, which is precisely why when you do need them — working with file permissions, encoding/decoding binary protocols, implementing hash functions — the knowledge gap can be costly.

The most dangerous gotcha is sign extension with the signed right shift >> on negative numbers. When you shift -4 >> 1, the result is -2 (the sign bit is replicated as bits shift right). But -4 >>> 1 yields 1073741823 — an entirely different number because >>> fills with zeros regardless of the sign bit. Using >> where >>> was intended on bit patterns that represent unsigned quantities produces silently incorrect results that may not surface until the bug reaches production. Another common mistake: ^ is XOR, not exponentiation. 2 ^ 3 evaluates to 1, not 8. If you need Math.pow(2, 3), you must call it explicitly.

Bit flags are the most practical application. Using power-of-2 values as individual flag bits within a single integer — FLAG_READ = 1 << 0, FLAG_WRITE = 1 << 1, FLAG_EXECUTE = 1 << 2 — allows combining multiple flags via OR and checking individual flags via AND. Unix file permissions (rwxr-xr-x) are a canonical example: permissions & FLAG_READ checks if the read bit is set. This post covers all operators in detail, the flag and mask pattern for combining permissions, the failure scenarios from sign extension to XOR swap edge cases, and the security considerations for bit-level permission checks and constant-time cryptographic operations.

When to Use / Not to Use

Use bitwise operators when:

  • Working with flags and bit masks (e.g., file permissions, configuration)
  • Performing cryptographic operations
  • Implementing efficient data structures (sets, compression)
  • Writing high-performance numeric algorithms
  • Encoding/decoding data at the bit level

Do not use bitwise operators when:

  • Working with non-integer types without explicit conversion
  • Performing arithmetic where semantic meaning matters
  • Dealing with signed negative numbers (behavior can be surprising with >>>)
  • Code readability is more important than micro-optimization

Diagram: Bitwise Operations at the Bit Level

graph LR
    A["1010"] --> B["& AND"]
    C["1100"] --> B
    B --> D["1000"]

    E["1010"] --> F["| OR"]
    C --> F
    F --> G["1110"]

    H["1010"] --> I["^ XOR"]
    C --> I
    I --> J["0110"]

    K["1010"] --> L["~ NOT"]
    L --> M["0101"]

    N["0101 << 1"] --> O["1010"]
    P["1010 >> 1"] --> Q["0101"]

Code Snippet: Flags and Masks Pattern

public class BitwiseDemo {
    // Define flags as powers of 2 for bit mask operations
    public static final int FLAG_READ = 1 << 0;   // 0001
    public static final int FLAG_WRITE = 1 << 1;  // 0010
    public static final int FLAG_EXECUTE = 1 << 2; // 0100
    public static final int FLAG_ADMIN = 1 << 3;  // 1000

    public static void main(String[] args) {
        int permissions = FLAG_READ | FLAG_WRITE; // 0011

        // Check if a flag is set
        boolean canRead = (permissions & FLAG_READ) != 0; // true
        boolean canExecute = (permissions & FLAG_EXECUTE) != 0; // false

        // Add a flag
        permissions |= FLAG_EXECUTE; // 0111

        // Remove a flag
        permissions &= ~FLAG_EXECUTE; // 0011

        // Toggle a flag
        permissions ^= FLAG_EXECUTE; // 0111 -> 0011
        permissions ^= FLAG_EXECUTE; // 0011 -> 0111

        // Signed right shift vs unsigned
        int negative = -4; // Binary: 11111111111111111111111111111100
        System.out.println(">> 2: " + (negative >> 2)); // -1 (sign-extended)
        System.out.println(">>> 2: " + (negative >>> 2)); // 1073741823 (zero-filled)

        // Common use: checking even/odd
        int number = 42;
        boolean isEven = (number & 1) == 0; // Faster than % operation

        // Swapping values without temp variable
        int a = 5, b = 9;
        a ^= b;
        b ^= a;
        a ^= b; // a = 9, b = 5
    }
}

Failure Scenarios

ScenarioProblemSolution
Using >> on negative numbersSign extension produces unexpected resultsUse >>> for unsigned right shift
Confusing ^ with exponentiation^ is XOR, not power operatorUse Math.pow() for exponentiation
Bitmask with non-power-of-2Overlapping bits cause incorrect resultsAlways use distinct powers of 2
Negative bit shift amountsShift amount must be non-negativeValidate shift amount before operation

Trade-off Table

OperatorDescriptionUse Case
&Bitwise ANDMask specific bits
|Bitwise ORSet bits
^Bitwise XORToggle bits, swap without temp
~Bitwise NOTCreate bit masks (flip all bits)
<<Left shiftMultiply by 2^n efficiently
>>Signed right shiftDivide by 2^n (floor for negative)
>>>Unsigned right shiftDivide by 2^n (logical shift)

Observability Checklist

  • Log flag state changes for permission-related operations
  • Add assertions when checking flag combinations
  • Instrument bit manipulation for cryptographic operations
  • Monitor for unexpected signed shift behavior in negative number paths
  • Add unit tests for bitmask operations covering edge cases

Security Notes

  • Bit-level permission checks: Ensure bitmask comparisons are not vulnerable to TOCTOU (time-of-check-time-of-use) race conditions
  • Cryptographic key handling: XOR operations on keys should be constant-time to prevent side-channel attacks
  • Flag manipulation in access control: Validate that flag constants are never reused or overlapping

Pitfalls

  1. Sign extension with >>: -4 >> 1 returns -2, not 2. Use >>> for logical shift.
  2. ^ is XOR, not exponentiation: 2 ^ 3 returns 1, not 8. Use Math.pow().
  3. Negative shift amounts: Shift amount must be non-negative. -1 << 2 is valid; -1 << -2 throws NegativeArraySizeException in some JVM versions.
  4. Bitwise ops on negative numbers: Results can be counterintuitive. Document assumptions.
  5. Width of operations: All bitwise operations work on 32-bit int or 64-bit long. Smaller types are promoted.

Quick Recap

  • Bitwise &, |, ^ operate on individual bits
  • << and >> shift bits left/right with sign extension
  • >>> shifts right with zero fill (unsigned)
  • ~ flips all bits
  • Use power-of-2 values for flags to prevent overlap
  • Always use >>> when dealing with bit patterns that should be treated as unsigned

Interview Questions

1. What is the difference between `>>` and `>>>` in Java?

Model Answer: "`>>` is signed right shift— it preserves the sign bit (sign extension). `-4 >> 1 = -2`. `>>>` is unsigned right shift— it always fills with zero. `-4 >>> 1 = 1073741823`. Use `>>>` when working with bit patterns that should not be interpreted as negative numbers."

2. How do you check if a specific bit is set in a number?

Model Answer: "Use the AND operator with a bitmask. For example, to check bit 3: `(value & (1 << 3)) != 0`. The `1 << 3` creates a mask with bit 3 set. If both bits are 1, the result is non-zero."

3. What is the XOR swap algorithm and why doesn't it always work?

Model Answer: "XOR swap uses `a ^= b; b ^= a; a ^= b;` to swap values without a temporary variable. It fails when `a` and `b` reference the same memory location because `x ^= x` sets the value to 0, not preserves it. Modern compilers optimize temp-variable swaps anyway."

4. What is a bitmask and when would you use one?

Model Answer: "A bitmask is a number with specific bits set used to extract, set, or toggle bits in another number. Common uses: storing multiple boolean flags in a single integer (like Unix file permissions `rwx`), checking multiple states simultaneously, and implementing sets efficiently."

5. What does `~5` evaluate to in Java?

Model Answer: "`~5` evaluates to `-6`. Bitwise NOT flips all bits. `5` in 32-bit binary is `00000000000000000000000000000101`. Flipping gives `11111111111111111111111111111010`, which is `-6` in two's complement representation."

6. What is the result of `1 << 3`?

Model Answer: "`1 << 3` equals `8`. Left shift shifts bits left by the specified amount, filling with zeros on the right. Each left shift effectively multiplies by 2. `1 << n` is equivalent to `2^n`."

7. Why is `number & 1` a fast way to check even/odd?

Model Answer: "In binary, the least significant bit of an even number is `0` and odd number is `1`. `number & 1` masks only that bit. If the result is `0`, the number is even; if `1`, it's odd. This is faster than `number % 2` because it's a single bitwise AND instead of division."

8. What is the difference between `^` and `**` (exponentiation)?

Model Answer: "`^` in Java is the bitwise XOR operator, NOT exponentiation. `2 ^ 3` returns `1` (binary `10` XOR `11 = 01`). For exponentiation, use `Math.pow(2, 3)` which returns `8.0`. Confusing these is a common bug."

9. What happens when you shift by more than 31 bits on an int?

Model Answer: "Java masks the shift amount with `31` for int (or `63` for long): `x << 32` is equivalent to `x << 0`, which means no shift occurs. This is defined behavior—the JVM internally uses `shiftAmount & 0x1F` for int."

10. How do you set a specific bit to 1 in a number?

Model Answer: "Use bitwise OR with a mask that has the target bit set: `value | (1 << bitPosition)`. For example, to set bit 3: `value | 0b1000`. This leaves all other bits unchanged while forcing the target bit to `1`."

11. How do you clear (set to 0) a specific bit in a number?

Model Answer: "Use bitwise AND with a mask that has the target bit cleared: `value & ~(1 << bitPosition)`. For example, to clear bit 3: `value & ~0b1000`. The `~` flips the mask so only the target bit is `0`, all others are `1` (preserving them through AND)."

12. What is sign extension with `>>` on negative numbers?

Model Answer: "Signed right shift (`>>`) replicates the sign bit on the left side. For `-8 >> 1`, the sign bit (1) is replicated as bits shift right: `-8 >> 1 = -4`. The result maintains the negative sign. Unsigned shift `>>>` always fills with zeros, regardless of sign."

13. What is the result of `5 << 3` in Java?

Model Answer: "`5 << 3` equals `40`. Left shift moves bits left by 3 positions, filling with zeros on the right. `5 << 3` is equivalent to `5 * 2^3 = 5 * 8 = 40`. If the shifted result exceeds the type's bit width, overflow wraps according to the type's range."

14. How does bitwise XOR differ from bitwise OR?

Model Answer: "XOR (exclusive OR) returns `1` only when bits differ: `1 ^ 0 = 1`, `1 ^ 1 = 0`, `0 ^ 0 = 0`. OR (inclusive OR) returns `1` when at least one bit is `1`: `1 | 0 = 1`, `1 | 1 = 1`, `0 | 0 = 0`. In binary: `1010 ^ 1100 = 0110`, but `1010 | 1100 = 1110`."

15. What is the complement operator and what does `~5` produce?

Model Answer: iThe bitwise complement (`~`) flips all bits of the operand. `~5` on a 32-bit integer (binary `00000000000000000000000000000101`) produces `-6` (binary `11111111111111111111111111111010`). This is the two's complement representation of `-6`."

16. What is the unsigned right shift result for `-1 >>> 1`?

Model Answer: "`-1 >>> 1` equals `2147483647` (Integer.MAX_VALUE). `-1` in 32-bit two's complement is all 1s (`11111111111111111111111111111111`). Unsigned right shift fills with zeros, producing `01111111111111111111111111111111`, which is `2147483647`."

17. How do you toggle a specific bit in a number?

Model Answer: "Use XOR with a bitmask where only the target bit is set: `value ^ (1 << bitPosition)`. For example, to toggle bit 3: `value ^ 0b1000`. If the bit was 1, it becomes 0; if it was 0, it becomes 1. Toggling the same bit twice restores the original value."

18. What is the difference between `1 << 31` and `(1L << 31)`?

Model Answer: "`1 << 31` is an `int` expression that overflows because `1` is `int`, and `1 << 31` produces `-2147483648` (Integer.MIN_VALUE, a negative number). `(1L << 31)` is a `long` expression producing `2147483648L` (positive). For bit patterns involving the high bit, use `long` to avoid signed int overflow."

19. How do you count the number of set bits (population count) in Java?

Model Answer: "Use `Integer.bitCount(n)` or `Long.bitCount(n)` for fast bit counting. For example, `Integer.bitCount(0b10110011)` returns `5` (the number of 1 bits). This uses hardware intrinsics where available and is much faster than manual loops."

20. What is the difference between `>>>` and `>>` when shifting negative numbers?

Model Answer: "For negative numbers, `>>` performs sign extension (fills with 1s), preserving the negative sign. `>>>` always fills with zeros (logical shift). For `-4 >> 1` you get `-2`; for `-4 >>> 1` you get `1073741823`. Use `>>>` when treating the bits as an unsigned value."

Further Reading

Conclusion

Bitwise operators give you fine-grained control over individual bits, making them indispensable for flag-based permissions systems, network protocol implementations, and performance-critical numeric algorithms. The key insight is treating flags as power-of-2 values to prevent overlapping bits and using XOR for efficient swapping.

Watch out for sign extension with the signed right shift >> on negative numbers—use >>> for logical shifts where the sign bit should not be preserved. Remember that ^ is XOR, not exponentiation; if you need 2^3 = 8, use Math.pow().

These operators complement arithmetic operators at the bit level and are often used alongside break and continue with labels in low-level control flow scenarios. For most application-level code, the readability cost rarely justifies the performance gain—but in embedded systems, cryptography, and compression, these operators are essential.

Category

Related Posts

Abstract Classes in Java

Learn about partially implemented classes that define contracts for subclasses using abstract methods and concrete implementations.

#java-abstract-classes #java #java-fundamentals

Arithmetic Operators in Java

Master Java arithmetic operators: addition, subtraction, multiplication, division, and modulo with integer division gotchas and operator precedence explained.

#java-arithmetic-operators #java #java-fundamentals

Array Basics in Java

Learn Java array fundamentals: declaration, initialization, element access, and the length property explained simply.

#java-array-basics #java #java-fundamentals