JB Header

Java Bitwise and Shift Operators with Examples

Introduction Every integer is stored as a pattern of bits - 0s and 1s. Bitwise and shift operators work directly on those bits. They are used for flags and permissions, colors, network addresses, hashing, and fast arithmetic. This tutorial explains Java's bitwise and shift operators with examples. We will start with how integers are stored in binary, including negative numbers. We will then look at the four bitwise operators - AND, OR, XOR and NOT - and the three shift operators. Lastly, we will see the most common practical uses - storing several yes/no flags in one number, and extracting parts of a value with masks.

(Note - This tutorial builds on Arithmetic, Relational and Logical OperatorsClick to read tutorial: Java Arithmetic, Relational and Logical Operators and on binary literals from Java LiteralsClick to read tutorial: Java Literals: Integer, Floating-Point, char and boolean.) How integers are stored in binary An int is 32 bits. Positive numbers are stored as ordinary binary - 12 is 1100, with 28 zeros in front. Negative numbers use two's complement: the leftmost bit is the sign bit (1 for negative), and -x is stored as "invert all the bits of x, then add 1". So -1 is 32 ones. Integer.toBinaryString() shows the bits of a number, which is how we will see what each operator does. The bitwise operators - &, |, ^ and ~ The bitwise operators compare two numbers bit by bit, at each position -
  • & (AND) - the result bit is 1 only if both bits are 1.
  • | (OR) - the result bit is 1 if either bit is 1.
  • ^ (XOR) - the result bit is 1 if the bits are different.
  • ~ (NOT, or complement) - works on one number, and flips every bit.
The bitwise operators
//BitwiseOps.java
public class BitwiseOps {
  static String bits(int n) {
    // the lowest 8 bits, padded with leading zeros
    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));
    System.out.println("a | b  = " + bits(a | b) + " = " + (a | b));
    System.out.println("a ^ b  = " + bits(a ^ b) + " = " + (a ^ b));
    System.out.println("~a     = " + (~a) + " (all 32 bits flipped)");
    System.out.println("~a + 1 = " + (~a + 1));
    System.out.println("-1     = " + Integer.toBinaryString(-1));
  }
}
 OUTPUT of the above code
a      = 00001100 = 12
b      = 00001010 = 10
a & b  = 00001000 = 8
a | b  = 00001110 = 14
a ^ b  = 00000110 = 6
~a     = -13 (all 32 bits flipped)
~a + 1 = -12
-1     = 11111111111111111111111111111111
Explanation of the code
  • Line up the bits of 12 and 10. Only the bit worth 8 is 1 in both, so 12 & 10 is 8. The bits worth 8, 4 and 2 are 1 in at least one, so 12 | 10 is 14. The bits worth 4 and 2 differ, so 12 ^ 10 is 6.
  • ~a flips all 32 bits, including the sign bit, so ~12 is -13. In general ~x equals -x - 1, which is why ~a + 1 gives -12 - the two's complement rule in action.
  • Do not confuse & and | with the logical operators && and ||. Used with booleans, & and | work as logical operators but without short-circuiting.
The shift operators - <<, >> and >>> Shift operators move all the bits of a number left or right by a given number of positions -
  • << (left shift) - moves bits left, filling with 0s on the right. Each shift left by one multiplies by 2.
  • >> (signed right shift) - moves bits right, filling on the left with copies of the sign bit. Each shift right by one divides by 2, rounding down, and keeps negative numbers negative.
  • >>> (unsigned right shift) - moves bits right, always filling with 0s. For negative numbers the result is a large positive number.
The shift operators
//ShiftOps.java
public class ShiftOps {
  public static void main(String[] args) {
    int x = 5;          // 101
    System.out.println("5 << 1   = " + (x << 1) + "  (" + Integer.toBinaryString(x << 1) + ")");
    System.out.println("5 << 3   = " + (x << 3) + " (" + Integer.toBinaryString(x << 3) + ")");
    System.out.println("40 >> 2  = " + (40 >> 2));
    System.out.println("7 >> 1   = " + (7 >> 1));

    int n = -16;
    System.out.println("-16 >> 2  = " + (n >> 2));
    System.out.println("-16 >>> 2 = " + (n >>> 2));
    System.out.println("-16       = " + Integer.toBinaryString(n));
    System.out.println("-16 >>> 2 = " + Integer.toBinaryString(n >>> 2));

    System.out.println("1 << 31  = " + (1 << 31));
    System.out.println("1 << 32  = " + (1 << 32) + " (shift distance is taken modulo 32)");
  }
}
 OUTPUT of the above code
5 << 1   = 10  (1010)
5 << 3   = 40 (101000)
40 >> 2  = 10
7 >> 1   = 3
-16 >> 2  = -4
-16 >>> 2 = 1073741820
-16       = 11111111111111111111111111110000
-16 >>> 2 = 111111111111111111111111111100
1 << 31  = -2147483648
1 << 32  = 1 (shift distance is taken modulo 32)
Explanation of the code
  • 5 << 3 is 5 × 23 = 40, and 40 >> 2 is 40 ÷ 22 = 10. 7 >> 1 is 3 - the remainder is dropped.
  • -16 >> 2 keeps the sign and gives -4. -16 >>> 2 fills with zeros, so the sign bit becomes 0, and the result is a large positive number. The two leading 1s have disappeared from its binary form.
  • 1 << 31 moves the 1 into the sign bit, giving Integer.MIN_VALUE.
  • For an int, only the lowest 5 bits of the shift distance are used, so shifting by 32 is the same as shifting by 0. For a long, the lowest 6 bits are used.
Note - byte, short and char values are promoted to int before any bitwise or shift operation, so the result is an int.
Practical use 1 - flags in a single number Each bit of an int can stand for a separate yes/no setting - a flag. Define each flag as a different power of two, then -
  • set a flag with |,
  • check a flag with &,
  • clear a flag with & ~,
  • and toggle a flag with ^.
Storing permissions as bit flags
//Permissions.java
public class Permissions {
  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 + ")");
    perms = perms | EXECUTE;                  // set EXECUTE
    System.out.println("add execute   : " + describe(perms) + " (" + perms + ")");
    perms = perms & ~WRITE;                   // clear WRITE
    System.out.println("remove write  : " + describe(perms) + " (" + perms + ")");
    perms = perms ^ READ;                     // toggle READ
    System.out.println("toggle read   : " + describe(perms) + " (" + perms + ")");
    System.out.println("can execute?  : " + ((perms & EXECUTE) != 0));
  }
}
 OUTPUT of the above code
start         : rw- (3)
add execute   : rwx (7)
remove write  : r-x (5)
toggle read   : --x (4)
can execute?  : true
This is how file permissions work on Linux and macOS - rwx for read, write and execute. Java's own java.util.EnumSet class uses the same technique internally, and is usually the more readable choice in application code. Practical use 2 - extracting parts with masks A mask is a number with 1s in the bit positions you want to keep. Shifting right and then AND-ing with a mask pulls out one part of a packed value - here, the red, green and blue parts of a color.
Extracting the parts of an RGB color
//ColorParts.java
public class ColorParts {
  public static void main(String[] args) {
    int orange = 0xFF8C00;
    int red = (orange >> 16) & 0xFF;
    int green = (orange >> 8) & 0xFF;
    int blue = orange & 0xFF;
    System.out.println("red = " + red + ", green = " + green + ", blue = " + blue);

    int rebuilt = (red << 16) | (green << 8) | blue;
    System.out.println("rebuilt = 0x" + Integer.toHexString(rebuilt).toUpperCase());
    System.out.println("12 is odd? " + ((12 & 1) == 1) + ", 13 is odd? " + ((13 & 1) == 1));
  }
}
 OUTPUT of the above code
red = 255, green = 140, blue = 0
rebuilt = 0xFF8C00
12 is odd? false, 13 is odd? true
Explanation of the code
  • 0xFF is a mask of eight 1s. (orange >> 16) & 0xFF moves the red byte to the bottom and keeps only those 8 bits.
  • << and | do the reverse, packing the three parts back into one number.
  • n & 1 keeps only the lowest bit, which is 1 for odd numbers - a common alternative to n % 2.
Summary In this tutorial we first saw how integers are stored in binary, with two's complement for negative numbers. We then used the bitwise operators &, |, ^ and ~, and saw that ~x equals -x - 1. Next we used the shift operators <<, >> and >>>, which multiply and divide by powers of two, and saw how they treat the sign bit. Lastly, we used bit flags to store permissions in a single number, and masks to extract the parts of a color. In the next tutorial, we will look at assignment, increment/decrement and ternary operatorsClick to read tutorial: Java Assignment, Increment/Decrement and Ternary Operators.