Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Bitwise operators

Every whole number is stored in memory as a sequence of bits — zeros and ones. Bitwise operators work not with the number as a whole but with each of its bits separately. They are used for flags, masks, data encoding and fast calculations.

Binary form

Integer.toBinaryString() shows a number in binary. In code, a binary number is written with the 0b prefix:

void main() {
    IO.println(Integer.toBinaryString(5));
    IO.println(Integer.toBinaryString(12));
    IO.println(0b1010);
}

Output:

101
1100
10

To turn a string of zeros and ones back into a number, use Integer.parseInt("1010", 2) — the second argument is the base.

AND, OR, exclusive OR

These operators compare the bits of two numbers pair by pair. & (AND) gives 1 only if both bits are 1; | (OR) — if at least one is 1; ^ (exclusive OR, XOR) — if the bits differ:

void main() {
    int a = 0b1100;
    int b = 0b1010;
    IO.println(Integer.toBinaryString(a & b));
    IO.println(Integer.toBinaryString(a | b));
    IO.println(Integer.toBinaryString(a ^ b));
}

Output:

1000
1110
110

Do not confuse them with the logical && and || from the operators lesson: those work with boolean and skip the right side when the answer is already known.

Inversion ~

The ~ operator flips every bit: 0 becomes 1 and 1 becomes 0. Since the highest bit of an int holds the sign, the result is negative: ~n always equals -n - 1:

void main() {
    IO.println(~5);
    IO.println(Integer.toBinaryString(~5));
}

Output:

-6
11111111111111111111111111111010

Shifts

<< shifts the bits left, filling in zeros on the right — that is multiplying by 2 for each position. >> shifts right and keeps the sign — dividing by 2. >>> also shifts right but always fills in zeros on the left, even for negative numbers:

void main() {
    IO.println(1 << 3);
    IO.println(40 >> 2);
    IO.println(-16 >> 2);
    IO.println(-16 >>> 28);
}

Output:

8
10
-4
15

Flags and masks

Each bit of a number can hold a separate yes/no property — a flag. A number with the bits you need set is called a mask. | turns a flag on, & checks it, and & ~ turns it off:

void main() {
    final int READ = 0b001;
    final int WRITE = 0b010;
    final int EXECUTE = 0b100;
 
    int access = READ | WRITE;
    IO.println("Read: " + ((access & READ) != 0));
    IO.println("Execute: " + ((access & EXECUTE) != 0));
 
    access = access & ~WRITE;
    IO.println(Integer.toBinaryString(access));
}

Output:

Read: true
Execute: false
1

One int fits 32 such flags. In everyday code an EnumSet is usually used instead of masks — there is a lesson about it in the collections chapter.

Common mistake

The != comparison runs before &. Without parentheses Java first computes WRITE != 0 and then tries to apply & to a number and a boolean:

void main() {
    int access = 0b011;
    int WRITE = 0b010;
    if (access & WRITE != 0) {
        IO.println("Writing allowed");
    }
}

Output:

Main.java:4: error: bad operand types for binary operator '&'
    if (access & WRITE != 0) {
               ^
  first type:  int
  second type: boolean
1 error
error: compilation failed

Always put the bitwise part in parentheses: (access & WRITE) != 0.

Thanks for reading!

Donate to the site — we work hard for you.