Understanding Bitwise and Shift Operators in Java
Course: Core Java Training
Topic: Understanding Bitwise and Shift Operators
Course Link: Core Java Training Course
Demo Link: Register for a Free Course Demo
Website: JustAcademy Official Website
1. Introduction to Bitwise and Shift Operators
Java provides several operators that work directly with the binary representation of integer values. These are called bitwise operators and shift operators. They allow developers to manipulate individual bits, perform low-level calculations, manage bit flags, and work with compact data representations.
Unlike arithmetic operators, which usually operate on complete numeric values, bitwise operators evaluate corresponding bits. Shift operators move bits to the left or right within an integer value.
These operators are particularly useful in low-level programming, networking, embedded systems, cryptography-related implementations, graphics, permissions, and performance-sensitive algorithms.
2. Learning Objectives
- Understand binary numbers and bit positions.
- Learn the purpose of Java's bitwise operators.
- Understand left shift, signed right shift, and unsigned right shift.
- Predict operator results using binary representations.
- Distinguish between bitwise and logical operators.
- Use bitwise operators in practical Java programs.
- Identify common mistakes and prepare for interview questions.
3. Understanding Binary Representation
Computers represent integer values using binary digits called bits. Each bit can have a value of either 0 or 1. Java's integer types use fixed-width binary representations.
For example, the decimal number 10 can be represented using four significant binary bits as 1010. In an 8-bit illustration, it is written as 00001010.
| Decimal Value |
8-Bit Binary Representation |
| 1 |
00000001 |
| 2 |
00000010 |
| 5 |
00000101 |
| 8 |
00001000 |
| 10 |
00001010 |
| 12 |
00001100 |
| 15 |
00001111 |
Important: The 8-bit representations in this table are for learning purposes. Java's byte uses 8 bits, short uses 16 bits, int uses 32 bits, and long uses 64 bits.
4. What Are Bitwise Operators?
Bitwise operators compare or manipulate individual bits of integral values. Java provides the following bitwise operators:
| Operator |
Name |
Purpose |
& |
Bitwise AND |
Produces 1 when both corresponding bits are 1. |
| |
Bitwise OR |
Produces 1 when at least one corresponding bit is 1. |
^ |
Bitwise XOR |
Produces 1 when corresponding bits are different. |
~ |
Bitwise complement |
Inverts every bit. |
<< |
Left shift |
Moves bits toward higher-order positions. |
>> |
Signed right shift |
Moves bits right while preserving the sign bit. |
>>> |
Unsigned right shift |
Moves bits right and fills left positions with zeros. |
5. Bitwise AND Operator (&)
The bitwise AND operator compares corresponding bits in two integer values. The result contains 1 only when both input bits are 1.
5.1 Truth Table
| First Bit |
Second Bit |
Result |
| 0 |
0 |
0 |
| 0 |
1 |
0 |
| 1 |
0 |
0 |
| 1 |
1 |
1 |
5.2 Example
public class BitwiseAndExample {
public static void main(String[] args) {
int a = 10;
int b = 12;
System.out.println(a & b);
}
}
Binary calculation:
10 = 00001010
12 = 00001100
--------
AND 00001000
Result = 8
Output:
8
5.3 Common Uses
- Checking whether a particular bit is set.
- Extracting selected bits from an integer.
- Working with bit flags and permission values.
- Applying bit masks to binary data.
5.4 Checking Whether a Number Is Even
public class EvenCheck {
public static void main(String[] args) {
int number = 14;
if ((number & 1) == 0) {
System.out.println("Even number");
} else {
System.out.println("Odd number");
}
}
}
Explanation: The least significant bit of an even integer is 0, while that of an odd integer is 1. Therefore, checking number & 1 determines whether the number is even or odd. This example assumes a standard Java int value.
6. Bitwise OR Operator (|)
The bitwise OR operator compares corresponding bits and produces 1 when either bit or both bits are 1. It produces 0 only when both input bits are 0.
6.1 Truth Table
| First Bit |
Second Bit |
Result |
| 0 |
0 |
0 |
| 0 |
1 |
1 |
| 1 |
0 |
1 |
| 1 |
1 |
1 |
6.2 Example
public class BitwiseOrExample {
public static void main(String[] args) {
int a = 10;
int b = 12;
System.out.println(a | b);
}
}
Binary calculation:
10 = 00001010
12 = 00001100
--------
OR 00001110
Result = 14
Output:
14
6.3 Setting a Specific Bit
Bitwise OR can set a selected bit to 1 without changing other bits that are not selected by the mask.
public class SetBitExample {
public static void main(String[] args) {
int number = 8; // 1000 in binary
int mask = 2; // 0010 in binary
int result = number | mask;
System.out.println(result);
}
}
Output:
10
The mask has its second-lowest bit set. Applying OR turns that bit on, producing binary 1010, which is decimal 10.
7. Bitwise XOR Operator (^)
The exclusive OR (XOR) operator produces 1 when corresponding bits differ. If the bits are the same, the result is 0.
7.1 Truth Table
| First Bit |
Second Bit |
Result |
| 0 |
0 |
0 |
| 0 |
1 |
1 |
| 1 |
0 |
1 |
| 1 |
1 |
0 |
7.2 Example
public class BitwiseXorExample {
public static void main(String[] args) {
int a = 10;
int b = 12;
System.out.println(a ^ b);
}
}
Binary calculation:
10 = 00001010
12 = 00001100
--------
XOR 00000110
Result = 6
Output:
6
7.3 Toggling a Bit
XOR can toggle a selected bit. If a bit is 0, XOR with 1 changes it to 1. If it is 1, XOR with 1 changes it to 0.
public class ToggleBitExample {
public static void main(String[] args) {
int number = 10; // 1010
int mask = 2; // 0010
int result = number ^ mask;
System.out.println(result);
}
}
Output:
8
The second-lowest bit changes from 1 to 0, so 1010 becomes 1000.
7.4 Important XOR Properties
a ^ 0 returns a.
a ^ a returns 0.
a ^ b is equal to b ^ a.
- XOR is useful for parity calculations and selected bit-manipulation algorithms.
8. Bitwise Complement Operator (~)
The bitwise complement operator, written as ~, reverses every bit in an integer value. Each 0 becomes 1, and each 1 becomes 0.
Java represents signed integers using two's complement. For an int, which has 32 bits, the identity ~x == -x - 1 holds for every integer value.
8.1 Example
public class ComplementExample {
public static void main(String[] args) {
int number = 5;
System.out.println(~number);
}
}
Output:
-6
Explanation: The 32-bit representation of 5 begins with zeros and ends with 0101. Complementing every bit changes its representation to the two's-complement representation of -6.
~5 = -5 - 1
= -6
8.2 Complement Formula
For an integer x:
~x = -x - 1
This formula is useful for predicting the result without writing all 32 bits.
9. Understanding Shift Operators
Shift operators move bits to different positions. They are useful for extracting fields, encoding values, decoding binary formats, and implementing bit-based algorithms.
Java supports three shift operators:
<< — left shift.
>> — signed right shift.
>>> — unsigned right shift.
10. Left Shift Operator (<<)
The left shift operator moves the bits of an integer toward the higher-order side. Zeros are inserted into the vacated lower-order positions. Bits shifted beyond the width of the value are discarded.
10.1 Example
public class LeftShiftExample {
public static void main(String[] args) {
int number = 5;
System.out.println(number << 1);
System.out.println(number << 2);
System.out.println(number << 3);
}
}
Output:
10
20
40
10.2 Binary Explanation
5 = 00000101
5 << 1 = 00001010 = 10
5 << 2 = 00010100 = 20
5 << 3 = 00101000 = 40
For positive values where no significant bits are lost, shifting left by one position multiplies the value by 2. Shifting left by two positions multiplies it by 4.
10.3 Left Shift Formula
Conceptually, shifting left by n positions multiplies by \(2^n\), but the result is calculated using fixed-width integer arithmetic. Overflow can occur, so this multiplication relationship does not always hold for the final signed result.
number << n
10.4 Practical Example: Creating a Bit Mask
public class BitMaskExample {
public static void main(String[] args) {
int bitPosition = 4;
int mask = 1 << bitPosition;
System.out.println(mask);
}
}
Output:
16
The expression 1 << 4 produces the integer value 16, whose binary representation has only bit position 4 set, counting from zero at the rightmost bit.
11. Signed Right Shift Operator (>>)
The signed right shift operator moves bits toward the lower-order side. It preserves the sign by copying the original sign bit into the vacated high-order positions. This is known as sign extension.
- For non-negative numbers, zeros are inserted on the left.
- For negative numbers, ones are inserted on the left.
11.1 Example with a Positive Number
public class RightShiftExample {
public static void main(String[] args) {
int number = 20;
System.out.println(number >> 1);
System.out.println(number >> 2);
}
}
Output:
10
5
In this example, the bits move right, and the positive value is divided by powers of two with the result rounded down toward negative infinity. For positive integers, this is equivalent to integer division by the corresponding power of two.
11.2 Example with a Negative Number
public class NegativeRightShiftExample {
public static void main(String[] args) {
int number = -8;
System.out.println(number >> 1);
System.out.println(number >> 2);
}
}
Output:
-4
-2
The sign remains negative because the sign bit is extended into the newly vacated high-order positions.
11.3 Important Behavior
For signed right shift, the result is equivalent to division by a power of two rounded toward negative infinity. For example, -7 >> 1 produces -4, not -3.
12. Unsigned Right Shift Operator (>>>)
The unsigned right shift operator moves bits to the right and fills the newly vacated high-order positions with zeros, regardless of whether the original number was positive or negative.
Although the operator is called unsigned right shift, it does not change the declared Java type. An int result is still an int, and a long result is still a long.
12.1 Example with a Positive Number
public class UnsignedShiftPositiveExample {
public static void main(String[] args) {
int number = 20;
System.out.println(number >>> 1);
}
}
Output:
10
For a positive number, >> and >>> usually produce the same result because the sign bit is already zero.
12.2 Example with a Negative Number
public class UnsignedShiftNegativeExample {
public static void main(String[] args) {
int number = -8;
System.out.println(number >> 1);
System.out.println(number >>> 1);
}
}
Output:
-4
2147483644
Explanation: A Java int uses 32 bits. The value -8 has a leading sign bit of 1. The signed shift copies that bit, producing -4. The unsigned shift inserts a zero instead, so the resulting 32-bit pattern represents the positive number 2147483644.
13. Comparison of the Three Shift Operators
| Operator |
Direction |
Inserted Bits |
Typical Use |
<< |
Left |
Zeros on the right |
Moving bits to higher positions and creating masks. |
>> |
Right |
Copies the sign bit |
Signed integer bit manipulation. |
>>> |
Right |
Zeros on the left |
Operations requiring zero-fill right shifts. |
14. Shift Distance Rules in Java
Java does not use every bit of the right-hand operand to determine the shift distance. The effective shift distance depends on the type of the left-hand operand.
| Left Operand Type |
Bits Used from Shift Distance |
Effective Range |
int |
Lowest 5 bits |
0 to 31 |
long |
Lowest 6 bits |
0 to 63 |
For example, shifting an int by 32 positions is equivalent to shifting it by 0 positions because only the lowest five bits of the shift distance are used.
public class ShiftDistanceExample {
public static void main(String[] args) {
int number = 7;
System.out.println(number << 1);
System.out.println(number << 32);
System.out.println(number << 33);
}
}
Output:
14
7
14
Explanation: For an int, the effective shift distances are 1, 0, and 1 respectively. For a long, the effective distance is determined by the lowest six bits instead.
15. Bitwise Operators vs Logical Operators
Bitwise operators and logical operators may look similar, but they serve different purposes.
| Feature |
Bitwise Operators |
Logical Operators |
| Common operators |
&, |, ^, ~ |
&&, ||, ! |
| Primary purpose |
Manipulate individual bits of integral values. |
Evaluate Boolean conditions. |
| Operands |
Integral types for bitwise operations; &, |, and ^ also support Boolean operands. |
Boolean values and Boolean expressions. |
| Short-circuiting |
Single-character & and | do not short-circuit Boolean expressions. |
&& and || may skip evaluating the second operand. |
| Example |
5 & 3 gives 1. |
true && false gives false. |
15.1 Example
public class LogicalVsBitwiseExample {
public static void main(String[] args) {
int a = 5;
int b = 3;
System.out.println(a & b);
System.out.println(a | b);
System.out.println(a ^ b);
boolean first = true;
boolean second = false;
System.out.println(first && second);
System.out.println(first || second);
}
}
Output:
1
7
6
false
true
16. Operator Precedence and Parentheses
Bitwise expressions can become difficult to read when several operators are combined. Parentheses make the intended evaluation order clear and help prevent mistakes.
public class PrecedenceExample {
public static void main(String[] args) {
int result1 = 5 | 2 & 1;
int result2 = (5 | 2) & 1;
System.out.println(result1);
System.out.println(result2);
}
}
Output:
5
1
Explanation: Bitwise AND has higher precedence than bitwise OR. Therefore, the first expression is evaluated as 5 | (2 & 1), which produces 5. In the second expression, the parentheses force 5 | 2 to be evaluated first, producing 7; then 7 & 1 produces 1.
Best practice: Use parentheses whenever an expression mixes bitwise operators, comparisons, or arithmetic operations and the intended grouping might be unclear.
17. Practical Example: Setting, Clearing, and Checking Bits
Bit masks let you manage individual bits within an integer. In the following example, bit positions are counted from zero, starting at the rightmost bit.
public class BitManipulationExample {
public static void main(String[] args) {
int flags = 0;
// Set bit 1
flags |= (1 << 1);
System.out.println(flags);
// Set bit 3
flags |= (1 << 3);
System.out.println(flags);
// Check whether bit 1 is set
boolean isSet = (flags & (1 << 1)) != 0;
System.out.println(isSet);
// Clear bit 1
flags &= ~(1 << 1);
System.out.println(flags);
// Toggle bit 3
flags ^= (1 << 3);
System.out.println(flags);
}
}
Output:
2
10
true
8
0
17.1 Explanation
flags |= (1 << 1) sets bit 1, resulting in 2.
flags |= (1 << 3) sets bit 3 as well, resulting in 10.
(flags & (1 << 1)) != 0 checks whether bit 1 is set.
flags &= ~(1 << 1) clears bit 1, leaving 8.
flags ^= (1 << 3) toggles bit 3 off, leaving 0.
18. Practical Example: Permission Flags
Bit flags can store several independent on/off settings in a single integer. Each flag uses a different bit position.
public class PermissionFlagsExample {
private static final int READ = 1; // 0001
private static final int WRITE = 2; // 0010
private static final int EXECUTE = 4; // 0100
public static void main(String[] args) {
int permissions = READ | WRITE;
System.out.println((permissions & READ) != 0);
System.out.println((permissions & WRITE) != 0);
System.out.println((permissions & EXECUTE) != 0);
permissions |= EXECUTE;
System.out.println((permissions & EXECUTE) != 0);
}
}
Output:
true
true
false
true
Explanation: The constants represent separate bits. Combining them with OR enables multiple permissions. AND checks whether a specific permission is enabled. This is an illustrative programming example; real security authorization should also enforce appropriate access controls.
19. Common Mistakes and Troubleshooting
| Mistake |
Why It Happens |
Correct Approach |
Confusing & with && |
One is bitwise AND; the other is short-circuit logical AND. |
Use the operator appropriate to the data and intention. |
Confusing | with || |
One performs bitwise OR; the other performs short-circuit logical OR. |
Use | for bit flags and || for Boolean conditions requiring short-circuiting. |
Assuming ~5 is 5's positive binary inverse |
Java uses a fixed-width signed representation. |
Remember that ~5 evaluates to -6 for an int. |
| Expecting right shifts of negative values to match division toward zero |
Signed right shift rounds the result toward negative infinity. |
Test negative values explicitly when implementing arithmetic logic. |
Assuming >> and >>> always match |
They differ when the sign bit is 1. |
Choose signed or zero-fill behavior deliberately. |
| Ignoring shift-distance masking |
Only the lowest five bits for int or six bits for long determine the shift distance. |
Validate shift distances if they come from external input or calculations. |
| Overlooking overflow in left shifts |
Bits shifted beyond the fixed-width type are discarded. |
Use a suitable numeric type and check the valid range. |
| Using a shift mask without considering signedness or position |
High-order bits can affect the signed result. |
Document bit positions and use carefully chosen masks. |
20. Best Practices
- Use meaningful constants for masks instead of unexplained numeric values.
- Document which bit position each flag represents.
- Use parentheses to make compound bitwise expressions easy to understand.
- Prefer descriptive helper methods when bit manipulation becomes complicated.
- Choose
>> when sign extension is intended and >>> when zero-fill behavior is intended.
- Test edge cases, including zero, negative values, the highest bit, and large shift distances.
- Be cautious when shifting into the sign bit of an
int or long.
- Do not assume bitwise code is automatically faster or more readable than a straightforward alternative.
21. Practice Exercises
Exercise 1: Bitwise AND
Predict the output before running the program.
int a = 7;
int b = 3;
System.out.println(a & b);
Expected Answer: 3
Exercise 2: Bitwise OR
int a = 4;
int b = 1;
System.out.println(a | b);
Expected Answer: 5
Exercise 3: Bitwise XOR
int a = 9;
int b = 5;
System.out.println(a ^ b);
Expected Answer: 12
Exercise 4: Complement
System.out.println(~10);
Expected Answer: -11
Exercise 5: Left Shift
System.out.println(3 << 3);
Expected Answer: 24
Exercise 6: Signed Right Shift
System.out.println(-12 >> 2);
Expected Answer: -3
Exercise 7: Unsigned Right Shift
System.out.println(-1 >>> 1);
Expected Answer: 2147483647
22. Mini Project: Bit Flag Manager
Build a small Java program that manages three settings: notifications, dark mode, and automatic updates. Each setting should be stored in a separate bit of an integer.
Project Requirements
- Create constants for the three flags.
- Enable a setting using bitwise OR.
- Disable a setting using AND with a complemented mask.
- Toggle a setting using XOR.
- Check the state of a setting using AND.
- Display the final flag value and the status of each setting.
Sample Implementation
public class BitFlagManager {
private static final int NOTIFICATIONS = 1 << 0;
private static final int DARK_MODE = 1 << 1;
private static final int AUTO_UPDATES = 1 << 2;
public static void main(String[] args) {
int settings = 0;
// Enable notifications and dark mode
settings |= NOTIFICATIONS;
settings |= DARK_MODE;
// Toggle automatic updates on
settings ^= AUTO_UPDATES;
System.out.println("Notifications: "
+ ((settings & NOTIFICATIONS) != 0));
System.out.println("Dark mode: "
+ ((settings & DARK_MODE) != 0));
System.out.println("Auto updates: "
+ ((settings & AUTO_UPDATES) != 0));
// Disable dark mode
settings &= ~DARK_MODE;
System.out.println("Updated settings: " + settings);
}
}
Expected Output:
Notifications: true
Dark mode: true
Auto updates: true
Updated settings: 5
This project demonstrates how multiple independent Boolean settings can be represented and manipulated using a single integer.
23. Interview Questions and Answers
Q1. What are bitwise operators in Java?
Bitwise operators work with the individual bits of integral values. Examples include AND (&), OR (|), XOR (^), and complement (~).
Q2. What is the difference between bitwise AND and logical AND?
Bitwise AND operates on corresponding bits for integral operands. Logical AND (&&) evaluates Boolean conditions and skips the second operand when the first condition is false.
Q3. What is the difference between OR and XOR?
OR returns 1 if at least one input bit is 1. XOR returns 1 only when the two input bits are different.
Q4. What does the complement operator do?
The ~ operator inverts every bit. For Java integer values, ~x is equivalent to -x - 1.
Q5. What is the difference between << and >>?
<< moves bits left and inserts zeros on the right. >> moves bits right and preserves the sign by extending the sign bit.
Q6. What is the difference between >> and >>>?
>> performs a signed right shift by extending the sign bit. >>> performs a zero-fill right shift, inserting zeros regardless of the sign.
Q7. What is the result of 5 << 2?
The result is 20. The binary representation of 5 is shifted two positions to the left, producing the value 20.
Q8. Why does ~5 return -6?
Java uses two's-complement signed integers. Complementing every bit follows the identity ~x = -x - 1, so ~5 equals -6.
Q9. How can you check whether a specific bit is set?
Use the expression (number & (1 << position)) != 0 to check the selected bit in a typical int mask, assuming a valid bit position from 0 through 31.
Q10. How can you set, clear, and toggle a bit?
- Set:
number |= (1 << position)
- Clear:
number &= ~(1 << position)
- Toggle:
number ^= (1 << position)
Q11. How is a shift distance handled for int and long?
Java uses the lowest five bits of the shift distance for an int and the lowest six bits for a long. Thus, the effective distances range from 0 to 31 for int and 0 to 63 for long.
Q12. Are bitwise operators always faster than arithmetic operators?
No. Modern Java compilers and runtime optimizations can efficiently handle many operations. Choose bitwise operators when they express the required logic clearly, and measure performance when optimization matters.
24. Quick Revision Checklist
- & — AND: 1 only when both bits are 1.
- | — OR: 1 when either bit is 1.
- ^ — XOR: 1 when bits differ.
- ~ — Complement: inverts every bit.
- << — Left shift: moves bits left and inserts zeros on the right.
- >> — Signed right shift: preserves the sign bit.
- >>> — Unsigned right shift: inserts zeros on the left.
- Set a bit:
number |= mask.
- Clear a bit:
number &= ~mask.
- Toggle a bit:
number ^= mask.
- Check a bit:
(number & mask) != 0.
- Remember that integer shifts use fixed-width arithmetic and can discard bits.
25. Conclusion
Bitwise and shift operators are important features of Java that allow precise manipulation of binary data. Bitwise AND, OR, XOR, and complement provide ways to inspect or modify individual bits, while left shift, signed right shift, and unsigned right shift move bits according to different rules.
Understanding binary representation, two's-complement integers, shift distances, and operator precedence makes these operations easier to use correctly. Practice with small binary examples before applying them to larger tasks such as flag management, masks, data encoding, and low-level algorithms.
To continue learning Java fundamentals and related programming concepts, explore the Core Java Training Course, register for a course demo, or visit the JustAcademy website.