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
OUTPUT of the above code
Explanation of the code
The shift operators - <<, >> and >>>
Shift operators move all the bits of a number left or right by a given number of positions -
OUTPUT of the above code
Explanation of the code
Practical use 1 - flags in a single number
Each bit of an
OUTPUT of the above code
This is how file permissions work on Linux and macOS - rwx for read, write and execute. Java's own
OUTPUT of the above code
Explanation of the code
(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));
}
}
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
- Line up the bits of 12 and 10. Only the bit worth 8 is 1 in both, so
12 & 10is 8. The bits worth 8, 4 and 2 are 1 in at least one, so12 | 10is 14. The bits worth 4 and 2 differ, so12 ^ 10is 6. ~aflips all 32 bits, including the sign bit, so~12is-13. In general~xequals-x - 1, which is why~a + 1gives-12- the two's complement rule in action.- Do not confuse
&and|with the logical operators&&and||. Used withbooleans,&and|work as logical operators but without short-circuiting.
<<(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)");
}
}
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)
5 << 3is 5 × 23 = 40, and40 >> 2is 40 ÷ 22 = 10.7 >> 1is 3 - the remainder is dropped.-16 >> 2keeps the sign and gives-4.-16 >>> 2fills 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 << 31moves the 1 into the sign bit, givingInteger.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 along, the lowest 6 bits are used.
byte, short and char values are promoted to int before any bitwise or shift operation, so the result is an int.
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));
}
}
start : rw- (3) add execute : rwx (7) remove write : r-x (5) toggle read : --x (4) can execute? : true
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));
}
}
red = 255, green = 140, blue = 0 rebuilt = 0xFF8C00 12 is odd? false, 13 is odd? true
0xFFis a mask of eight 1s.(orange >> 16) & 0xFFmoves 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 & 1keeps only the lowest bit, which is 1 for odd numbers - a common alternative ton % 2.
&, |, ^ 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.Java Fundamentals Tutorials
Java Arithmetic, Relational and Logical OperatorsClick to read tutorial: Java Arithmetic, Relational and Logical Operators Java Assignment, Increment/Decrement and Ternary OperatorsClick to read tutorial: Java Assignment, Increment/Decrement and Ternary Operators Java Syntax Basics: Statements, Identifiers, KeywordsClick to read tutorial: Java Syntax Basics: Statements, Identifiers, Keywords Variables in Java: Declaration, Initialization and ScopeClick to read tutorial: Variables in Java: Declaration, Initialization and Scope Java Primitive Data Types and Their Ranges with ExamplesClick to read tutorial: Java Primitive Data Types and Their Ranges with Examples Java Literals: Integer, Floating-Point, char and booleanClick to read tutorial: Java Literals: Integer, Floating-Point, char and boolean Type Conversion and Casting in Java with ExamplesClick to read tutorial: Type Conversion and Casting in Java with Examples
Java Arithmetic, Relational and Logical OperatorsClick to read tutorial: Java Arithmetic, Relational and Logical Operators Java Assignment, Increment/Decrement and Ternary OperatorsClick to read tutorial: Java Assignment, Increment/Decrement and Ternary Operators Java Syntax Basics: Statements, Identifiers, KeywordsClick to read tutorial: Java Syntax Basics: Statements, Identifiers, Keywords Variables in Java: Declaration, Initialization and ScopeClick to read tutorial: Variables in Java: Declaration, Initialization and Scope Java Primitive Data Types and Their Ranges with ExamplesClick to read tutorial: Java Primitive Data Types and Their Ranges with Examples Java Literals: Integer, Floating-Point, char and booleanClick to read tutorial: Java Literals: Integer, Floating-Point, char and boolean Type Conversion and Casting in Java with ExamplesClick to read tutorial: Type Conversion and Casting in Java with Examples