Skip to main content

Command Palette

Search for a command to run...

Java Operators & Bitwise Tricks

Arithmetic, increment/decrement, bitwise operations, masking, type casting in Java

Updated
7 min read
Java Operators & Bitwise Tricks

Arithmetic Operators and Expressions

Java gives you a small but powerful set of arithmetic operators. These work pretty much the way you’d expect:

  • + → Addition

  • - → Subtraction

  • / → Division

  • * → Multiplication

  • % → Modulus (returns the remainder after division)

You can use these operators on all numeric data types (byte, short, int, long, float, double, char), but not on boolean(Java refuses to treat true and false like numbers).

Operator Precedence (Highest → Lowest)

When you combine multiple operators in one expression, Java follows a fixed precedence order:

PrecedenceOperatorsMeaning
1* / %Multiplication, Division, Modulus
2+ -Addition, Subtraction

So in an expression like:

int x = 10 + 6 * 2;

Java always evaluates the * first, then applies the +, giving you 22.

If you want to override the default order, parentheses still rule the world.

Java’s Type Promotion Rules (Why Your byte Suddenly Becomes an int)

One thing Java loves to do (usually without asking) is promote smaller data types during arithmetic. So even if you start with tiny types like byte or short, the moment you add or subtract them, Java lifts them into bigger types behind the scenes. It’s part of what Java calls numeric promotion.

  • byte, short, and char all get promoted to int when used in an expression

    • byte + short → int

    • char + short → int

    • char + int → int

  • If either operand is long, the whole expression becomes long

    • short + long → long
  • If either side is a float, Java goes with float

    • int + float → float

    • long + float → float

  • And if a double enters the chat, everything becomes double

    • float + double → double

    • long + double → double

The idea is basically: Java always promotes to the “safer” type so nothing important gets lost.

Increment and Decrement Operators

Java gives us four operators to increase or decrease a value by 1. The only thing is when the increment/decrement happens.

  • Post-increment (i++) → use the value first, then increase it

  • Post-decrement (i--) → use the value first, then decrease it

  • Pre-increment (++i) → increase first, then use the value

  • Pre-decrement (--i) → decrease first, then use the value

Quick examples:

int x = 5;
System.out.println(x++); // prints 5, x becomes 6
System.out.println(++x); // x becomes 7, prints 7

int y = 10;
System.out.println(y--); // prints 10, y becomes 9
System.out.println(--y); // y becomes 8, prints 8

Bitwise Operators in Java — AND, OR, XOR, NOT, Shifts

Bitwise operators work directly on the binary representation of numbers. They’re super fast and great for low-level tasks like masks, flags, and performance-critical logic.

Main Bitwise Operators

OperatorSymbolMeaning
AND&Sets a bit to 1 only if both bits are 1
OR``Sets a bit to 1 if either bit is 1
XOR^Sets a bit to 1 if the bits are different
NOT~Flips every bit
Left Shift<<Shifts bits left (multiply by 2ⁿ)
Right Shift>>Arithmetic right shift (keeps sign bit)
Unsigned Right Shift>>>Logical right shift (fills with 0)

Truth Tables

AND (&)

ABA & B
000
010
100
111

OR (|)

AB**AB**
000
011
101
111

XOR (^)

ABA ^ B
000
011
101
110

Bitwise Examples

int x = 10, y = 6, z;
Binary:

  • x = 10 → 00001010

  • y = 6 → 00000110

AND

  00001010
& 00000110
-----------
  000000102

OR

  00001010
| 00000110
-----------
  0000111014

XOR

  00001010
^ 00000110
-----------
  0000110012

Shift Operators

int x = 10; // 00001010
int z;

Left Shift (<<)

x   =   00001010
x << 1 = 0001010020

General rule:
x << k → x * 2^k

Right Shift (>>) (keeps the sign bit)

x   =     00001010
x >> 1 = 000001015

General rule:
x >> k → x / 2^k

How Negative Numbers Are Stored (Two’s Complement)

Let’s store -10:

  1. Start with +10
    00001010

  2. Flip all bits (1’s complement)
    11110101

  3. Add 1 (2’s complement)
    11110110 → this represents -10 in binary

Since the first bit is 1, the number is negative.

Right Shift With Negative Numbers

x = -10 = 11110110
x >> 1  = 11111011  // sign bit stays 1
x >>> 1 = 01111011  // fills with 0 → 123

>>> always shifts in zero, even for negative numbers.

Bitwise NOT (~)

x = 00001010  // 10
~x= 11110101  // -11

The rule is:
~x = -(x + 1)

So:
~10 = -11

Bit Masking and Merging

Bit masking lets you check, set, or clear specific bits in an integer using bitwise operators. Think of it as controlling individual switches in a row of lights — you can flip only the ones you care about.

  • Masking (checking a bit):
int flags = 0b1010;    // 4 bits: 1010
int mask  = 0b0010;    // check 2nd bit

boolean isSet = (flags & mask) != 0;  // true, 2nd bit is 1
  • Merging (setting a bit):
int flags = 0b1000;
int mask  = 0b0010;

flags = flags | mask;   // set the 2nd bit
// flags = 1010

With just & and |, you can read and write bits efficiently, which is crucial in low-level programming, graphics, and flags handling.

Question: How to store 2 numbers in 1 byte?

A single byte is 8 bits, so if both numbers are small enough (≤ 4 bits each, i.e., 0–15), you can pack them together using bitwise operations.

Step 1: Define the numbers

byte a = 9;  // 4 bits max: 1001
byte b = 6;  // 4 bits max: 0110

Step 2: Pack them into 1 byte

byte packed = (byte) ((a << 4) | b);
  • a << 4 → move a to the higher 4 bits

  • | b → merge b into the lower 4 bits

a = 100110010000
b = 011000000110
packed = 10010110150 (decimal)

Step 3: Unpack the numbers

byte a2 = (byte) ((packed >> 4) & 0x0F);  // high 4 bits
byte b2 = (byte) (packed & 0x0F);         // low 4 bits

System.out.println(a2 + " " + b2);  // 9 6
  • >> 4 shifts high bits to low position

  • & 0x0F masks out unwanted bits

This way, you store two 4-bit numbers in a single byte and retrieve them later.

Widening and Narrowing (Type Casting)

Widening / Upcasting

  • Converts smaller type → bigger type automatically.

  • Safe, no data loss.

byte b = 10;
int i = b;  // byte → int (widening)

Narrowing / Downcasting

  • Converts bigger type → smaller type.

  • Must be explicit; can lose data.

int i = 130;
byte b = (byte) i;  // narrowing, b = -126

Question: How to swap two numbers without a Temp variable?

Bitwise XOR lets you swap numbers:

int a = 5, b = 9;

a = a ^ b;  // Step 1
b = a ^ b;  // Step 2
a = a ^ b;  // Step 3

System.out.println(a + " " + b);  // 9 5

No extra memory needed.