Java Bitwise Operators
Table of Contents + β
In the last lesson you learned about Java unary operators. Now we go deeper, down to the actual bits inside a number. Bitwise operators let you flip, shift, and combine the 1s and 0s a number is built from.
π€ Why look at the bits?
A computer stores every int as a row of 32 bits, each a single 1 or 0. Usually Java hides them. Sometimes the bits themselves are the data.
- Store ten yes-or-no settings in one number instead of ten booleans.
- Multiply or divide by powers of two faster than normal math.
- Check if a number is even without dividing.
Binary writes numbers using only 1 and 0. Each position is worth double the one on its right: 1, 2, 4, 8, 16, and so on.
5is101(one 4, zero 2s, one 1).6is110(one 4, one 2, zero 1s).
Integer.toBinaryString(n) turns a number into its binary text so you can read it. We use it a lot below.
System.out.println(Integer.toBinaryString(5));System.out.println(Integer.toBinaryString(6));Java drops the leading zeros, so you only see the meaningful part.
Output
101110π The bitwise operators at a glance
Java has seven bitwise operators. Here is the quick map; each gets its own example below.
| Operator | Name | What it does |
|---|---|---|
| & | AND | 1 only when both bits are 1 |
| | | OR | 1 when at least one bit is 1 |
| ^ | XOR | 1 when the two bits are different |
| ~ | complement | Flips every bit |
| << | left shift | Moves bits left, fills with 0 |
| >> | signed right shift | Moves bits right, keeps the sign |
| >>> | unsigned right shift | Moves bits right, fills with 0 |
The first four work bit by bit. The last three slide the whole row of bits left or right.
β The AND operator (&)
The bitwise AND operator & compares two numbers bit by bit:
- Result bit is
1only when both input bits are1. - Any
0in the pair gives0.
Here is the truth for a single pair of bits.
| A | B | A & B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
Letβs AND 12 and 10 together.
int a = 12; // 1100int b = 10; // 1010int result = a & b;System.out.println(Integer.toBinaryString(a));System.out.println(Integer.toBinaryString(b));System.out.println(Integer.toBinaryString(result));System.out.println(result);Line up the bits and check each column:
1100and1010, left to right: 1&1=1, 1&0=0, 0&1=0, 0&0=0.- Result is
1000, which is8.
Output
1100101010008So & keeps only the bits set in both numbers, which is perfect for checking flags later.
π΅ The OR operator (|)
The bitwise OR operator |:
- Result bit is
1when at least one of the two bits is1. - Only gives
0when both bits are0.
int a = 12; // 1100int b = 10; // 1010int result = a | b;System.out.println(Integer.toBinaryString(result));System.out.println(result);Check the columns: 1100 | 1010 gives 1, 1, 1, 0. Result is 1110, which is 14.
Output
111014So | collects every bit set in either number, which is the natural way to turn a setting on.
π The XOR operator (^)
The XOR operator ^ means βexclusive orβ:
- Result bit is
1only when the two bits are different. - Same bits (both 1 or both 0) give
0.
| A | B | A ^ B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
int a = 12; // 1100int b = 10; // 1010int result = a ^ b;System.out.println(Integer.toBinaryString(result));System.out.println(result);Column by column, 1100 ^ 1010 gives 0, 1, 1, 0. Result is 0110, which is 6.
Output
1106Remember this XOR habit: applying the same value twice cancels it out, so a ^ b ^ b equals a. That powers the XOR swap trick at the end.
π The complement operator (~)
The complement operator ~ works on one number:
- Flips every bit: each
1becomes0, each0becomes1. - It touches all 32 bits, so the result can look surprising.
int a = 5;int result = ~a;System.out.println(result);You get -6, not a small number, because Java stores negatives using twoβs complement.
- The rule that always holds:
~nequals-(n + 1). - So
~5is-(5 + 1)=-6, and~0is-1.
Output
-6Tip
An easy way to remember the result of ~ is the formula ~n == -(n + 1). So ~0 is -1, ~1 is -2, and ~-1 is 0.
β¬ οΈ The left shift operator
The left shift operator << slides every bit to the left:
- Gaps on the right fill with
0. - Each shift left doubles the number, since every bit moves to a position worth double.
int a = 3; // 11System.out.println(Integer.toBinaryString(a << 1));System.out.println(a << 1);System.out.println(a << 3);Start with 3, which is 11:
a << 1turns11into110=6(doubled).a << 3turns11into11000=24(3 times 8).- Pattern:
n << kequalsnmultiplied by 2 to the powerk.
Output
110624So << is a very fast way to multiply by powers of two.
β‘οΈ The signed right shift operator
The signed right shift operator >> slides bits to the right:
- Each shift right roughly halves the number, dropping any remainder.
- βSignedβ means it keeps the sign: positives fill with
0on the left, negatives fill with1, so negatives stay negative.
int a = 24; // 11000System.out.println(a >> 1);System.out.println(a >> 3);
int b = -24;System.out.println(b >> 1);24 >> 1gives12(24 / 2).24 >> 3gives3(24 / 8).-24 >> 1stays negative and gives-12.
Output
123-12So >> is a fast divide by a power of two that respects the sign.
β© The unsigned right shift operator
The unsigned right shift operator >>> also slides bits right:
- It always fills the left with
0, whatever the sign. - For positives it acts exactly like
>>. - The difference shows up only with negatives, where the sign bit is no longer protected.
int a = -8;System.out.println(a >> 1);System.out.println(a >>> 1);-8 >> 1stays negative and becomes-4.-8 >>> 1fills the left with0, so the old sign bit becomes data and the number turns into a very large positive value.
Output
-42147483644Reach for >>> when you treat a number as a raw row of bits, such as packing data or reading low-level formats.
π© Practical use: flags and bitmasks
Store several on/off settings inside one int instead of many booleans, each setting in its own bit. This is a bitmask.
- Give each setting a value that is a single bit.
- Turn a setting on with
|. - Check whether a setting is on with
&.
int DARK_MODE = 1; // 001int NOTIFICATIONS = 2; // 010int SOUND = 4; // 100
int settings = 0;settings = settings | DARK_MODE; // turn dark mode onsettings = settings | SOUND; // turn sound on
System.out.println(Integer.toBinaryString(settings));
// Check whether each setting is onSystem.out.println((settings & DARK_MODE) != 0);System.out.println((settings & NOTIFICATIONS) != 0);System.out.println((settings & SOUND) != 0);- Start with
0(all off), then|withDARK_MODEandSOUNDswitches both bits on, sosettingsbecomes101. - To check, AND
settingswith the settingβs bit; a non-zero result means it was on. - Dark mode and sound come back true; notifications, never turned on, comes back false.
Output
101truefalsetrueThis trick is everywhere in real software, from file permissions to graphics options, because it packs many switches into one tidy number.
βοΈ Practical use: even or odd, and the XOR swap
The last bit tells you instantly whether a number is even or odd, with no division:
- Last bit
1means odd;0means even. - So
n & 1keeps only the last bit and gives the answer.
int x = 7;int y = 10;System.out.println(x & 1); // 1 means oddSystem.out.println(y & 1); // 0 means even7 & 1is1(last bit set), so 7 is odd.10 & 1is0(last bit clear), so 10 is even.
Output
10Another classic trick swaps two numbers with XOR and no temporary variable. It leans on that XOR habit where applying a value twice cancels it out.
int p = 5;int q = 9;p = p ^ q;q = p ^ q;p = p ^ q;System.out.println(p);System.out.println(q);After the three XOR steps the values trade places: p holds the old q, and q holds the old p. Each step rebuilds one original value from the combined result.
Output
95Tip
The XOR swap is a fun trick to know, but in everyday code a simple temporary variable is clearer and just as fast. Reach for it mainly to understand how XOR behaves.
β οΈ Common Mistakes
A few bitwise traps catch nearly everyone early on.
Confusing & with &&. Single & works on bits and gives a number; double && combines booleans and gives true or false. They are not interchangeable.
// β Avoid: & on booleans works but does not short-circuit, and reads as a typo// if (user != null & user.isActive()) ...
// β
Good: use & for bit math on numbersint onlyLastBit = value & 1;
// β
Good: use && for combining conditionsif (user != null && user.isActive()) { System.out.println("Active");}Using >> when you needed >>>. The signed shift keeps the sign, so a negative stays negative. That surprises you when you mean to treat the value as raw bits.
// β Avoid: >> keeps the sign, so a negative stays negative// int wrong = -8 >> 1; // gives -4
// β
Good: >>> fills with zeros when you want a raw bit shiftint raw = -8 >>> 1; // gives a large positive numberForgetting that bitwise operators have low precedence. In Java, & and | bind looser than comparisons like ==, so a flag check without brackets does the wrong thing.
// β Avoid: this is read as settings & (DARK_MODE != 0), which is wrong// if (settings & DARK_MODE != 0) ...
// β
Good: wrap the bitwise part in bracketsif ((settings & DARK_MODE) != 0) { System.out.println("Dark mode is on");}β Best Practices
A few habits keep bit work clear and correct:
- Print bits while learning. Use
Integer.toBinaryString(n)to see what is happening, so the result is never a mystery. - Always bracket flag checks. Write
(settings & FLAG) != 0so precedence never bites you. - Use
&for bits and&&for conditions. Keep the single and double forms in their own lanes. - Name your bit constants. A name like
DARK_MODEis far clearer than a bare1scattered through the code. - Pick
>>for signed numbers and>>>for raw bits. Choose the shift that matches how you are treating the value.
π§© What Youβve Learned
Nice work. The key points:
- β
Numbers are stored as bits, and
Integer.toBinaryString(n)lets you read them. - β
&(AND) keeps bits set in both numbers;|(OR) keeps bits set in either;^(XOR) keeps bits that differ. - β
~(complement) flips every bit, and~nequals-(n + 1). - β
<<doubles by shifting left;>>halves while keeping the sign;>>>shifts right filling with zeros. - β
Bitwise tools power flags and bitmasks, even/odd checks with
& 1, and the XOR swap. - β Bracket flag checks because bitwise operators have low precedence.
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
What is the result of 12 & 10 in decimal?
Why: AND keeps only bits set in both. 1100 & 1010 is 1000, which is 8.
- 2
What does n << 3 do to a number?
Why: Each left shift doubles the value, so shifting left by 3 multiplies by 2 to the power 3, which is 8.
- 3
How can you tell if an int n is odd using bits?
Why: The last bit is 1 for odd numbers, so n & 1 keeps that bit and equals 1 when n is odd.
- 4
What is the difference between >> and >>> ?
Why: Signed right shift >> preserves the sign bit, while unsigned right shift >>> always fills the left side with zeros.
π Whatβs Next?
You can now work right down at the bit level. Next we look at a compact operator that picks between two values in a single line, a neat shortcut for short if-else choices.