# 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:

| Precedence | Operators | Meaning |
| --- | --- | --- |
| **1** | `*` `/` `%` | Multiplication, Division, Modulus |
| **2** | `+` `-` | Addition, Subtraction |

So in an expression like:

```java
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:**

```java
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**

| Operator | Symbol | Meaning |
| --- | --- | --- |
| 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 (**`&`)

| **A** | **B** | **A & B** |
| --- | --- | --- |
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |

### **OR (**`|`)

| **A** | **B** | **A | B** |
| --- | --- | --- |
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 1 |

### **XOR (**`^`)

| **A** | **B** | **A ^ B** |
| --- | --- | --- |
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |

## **Bitwise Examples**

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

* `x = 10 → 00001010`
    
* `y = 6 → 00000110`
    

### **AND**

```java
  00001010
& 00000110
-----------
  00000010 → 2
```

### **OR**

```java
  00001010
| 00000110
-----------
  00001110 → 14
```

### **XOR**

```java
  00001010
^ 00000110
-----------
  00001100 → 12
```

## **Shift Operators**

int x = 10; // 00001010  
int z;

### **Left Shift (**`<<`)

```java
x   =   00001010
x << 1 = 00010100 → 20
```

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

### **Right Shift (**`>>`) (keeps the sign bit)

```java
x   =     00001010
x >> 1 = 00000101 → 5
```

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**

```java
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 (**`~`)

```java
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):**
    

```java
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):**
    

```java
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**

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

### **Step 2: Pack them into 1 byte**

```java
byte packed = (byte) ((a << 4) | b);
```

* `a << 4` → move `a` to the **higher 4 bits**
    
* `| b` → merge `b` into the **lower 4 bits**
    

```java
a = 1001 → 10010000
b = 0110 → 00000110
packed = 10010110 → 150 (decimal)
```

---

### **Step 3: Unpack the numbers**

```java
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.
    

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

### **Narrowing / Downcasting**

* Converts **bigger type → smaller type**.
    
* Must be explicit; can lose data.
    

```java
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:

```java
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.
