Unit 1 home
UNIT 1 · ADD-ON MASTERCLASS THE COMPACTED SEVEN UNIT I · UI24PC320CS
ADD-ON · P 1/17PGDN NEXT POINT · PGUP BACK
K TRISHAANK · OOP THROUGH JAVA · UNIT I · ADD-ON MASTERCLASS · ORANGE

Seven ideas the exam always hides inside one question.

Unit 1 is officially closed — C12 shut the door and LAB 2 built the family in Eclipse. But seven ideas from this unit keep coming back compressed into single exam lines: a range you must derive, a bit you must predict, a shift on a negative number, a reference that secretly shares an object, a variable that refuses to default, a stack that quietly overflows, and a field owned by no object at all. Today all seven — traced bit by bit, frame by frame, box by box.

THE ARCranges & two's complement · OR/AND/XOR · shifts & ~ · value vs reference · the 4-segment memory map · recursion frames · static
TODAY'S SHAPE7 compacted topics · 40+ worked examples · every answer predicted BEFORE it is revealed
ONE COLOUR LANGUAGEBlue = 0 / positive · Amber = 1 / negative · Green = correct · Red = wrong step · Purple = static zone
FEEDSevery Unit-2+ topic that touches numbers, memory or method calls — and every placement aptitude round
C12 · UNIT-1 CLOSE LAB 2 · ECLIPSE ADD-ON · THE COMPACTED SEVEN — YOU ARE HERE UNIT 2

Why one extra class? Because these seven are exactly the topics that get asked as "predict the output" one-liners — System.out.println(5 & 9);, -5 >> 1, b.cost = 13; — and a one-liner gives you nowhere to hide. Each of the seven gets the same treatment: the rule, tiny examples first, then the traps — with every intermediate step drawn on screen, never skipped.

BLUE · bit 0 / positive AMBER · bit 1 / negative GREEN · correct RED · the exact wrong step PURPLE · static zone

This colour language never changes on this page. Learn it once, read every diagram for free.

PART 2 · WHAT TODAY DELIVERS

Seven compacted topics. One sitting.

This is a revision masterclass, not a first meeting — C2 introduced types, C9 introduced memory and static. Today compresses them to exam density and adds the three bit-level tools the syllabus assumes: two's complement, bitwise logic, and shifts.

BY THE END YOU CAN

  • Derivethe range of ANY signed type from one formula — including a type that doesn't exist.
  • Predicta|b, a&b, a^b and any shift — even on negative numbers — column by column, without guessing.
  • Tracewhat b = a really copies for an int versus a Car — and prove it with one line of output.
  • Placeany variable into the right memory segment from its LOCATION alone — and predict which ones refuse to default.
  • Reada recursive method as a stack of frames — and spot the missing base condition before the JVM does.

WHERE THIS SITS

TODAY'S ROUTE · 7 TOPICS · 17 STOPS

  • T1 · Data types + the universal range formula — and the fictional tap typeCORE
  • T1 · Two's complement — encode, decode, and the −8 that maps to itselfTRACE
  • T2 · OR / AND / XOR — three truth tables, six worked examplesCORE
  • T3 · Shifts << >> >>> + negation ~ — incl. the −5 trapsTRACE
  • T4 · Value vs reference — the photocopy and the two-names personCORE
  • T5 · The memory model — four segments, defaults, and the local that refusesCORE
  • T6 · Recursion — frames that stack, a base that saves, a break that breaksTRACE
  • T7 · Static — the field owned by the class, not the objectCORE
  • Practice sets — 4–5 questions per topic, solutions locked until you tryNOTEBOOK

UNIT 1 ADD-ON · 17 PAGES · ALL CORE · EVERY EXAMPLE FROM THE MASTER PLAN IS ON THIS PAGE

TOPIC 1 · PART 3 · DATA TYPES & THE UNIVERSAL RANGE FORMULA

Don't memorize the range. Build it.

Java is statically typed — unlike Python, which guesses the type from the value, you must reserve memory up front. For whole numbers Java gives four choices, and the ONLY real difference between them is how much memory each one reserves.

S1 · THE MEMORY TABLE — WATCH THE DOUBLING: 1 → 2 → 4 → 8 BYTES

byte81 byte · 8 bits
short882 bytes · 16 bits
int88884 bytes · 32 bits
long888888888 bytes · 64 bits

bits: 8 → 16 → 32 → 64 — the doubling is NOT a coincidence. It's how binary combinations scale.

THE FORMULA EVERY STUDENT MEMORIZES — AND FEW UNDERSTAND

UNIVERSAL RANGE FORMULA · ANY n-BIT SIGNED TYPE
MIN
−2(n−1)
MAX
+2(n−1) − 1
Today's goal: DERIVE this — so it can never be forgotten.

Meet tap — a data type that does not exist. To de-mystify the formula we invent our own type: tap reserves just 4 bits (half a byte). Small enough to write EVERY possible pattern on one screen — that's the whole trick.

S2 + S3 · ALL 16 COMBINATIONS OF 4 BITS — THEN THE MSB SPLIT

MSB = 0 → POSITIVE (BLUE)

0000 = 0
0001 = 1
0010 = 2
0011 = 3
0100 = 4
0101 = 5
0110 = 6
0111 = 7

Eight patterns start with 0 → they keep their plain binary value: 0 to 7.

MSB = 1 → NEGATIVE (AMBER)

1000 = ? (NOT 8!)
1001 = ?
1010 = ?
1011 = ?
1100 = ?
1101 = ?
1110 = ?
1111 = ?

Eight patterns start with 1 → the designers reserved these for negative numbers. Their values need decoding — next part.

4 bits → 2⁴ = 16 possible combinations, 0000 to 1111. If we only wanted positives: 0000→0 … 1111→15, range 0 to 15 — and 15 = 2⁴ − 1. That's where the formula's right side comes from.

The MSB (Most Significant Bit) split is a HUMAN decision baked into hardware — not a mathematical necessity. Naming it lets you reason about ANY bit width, not just 4-bit toys.

Why a raw sign-flip doesn't work

If MSB 1 simply meant "negative", you'd expect 1000 to be −8 by direct conversion… but reading 1000 as plain binary gives +8, not −8. Something else must happen to the bits before conversion. That something is two's complement — next part.

TOPIC 1 · PART 4 · TWO'S COMPLEMENT

Two directions, one dance: flip & add, subtract & flip.

Two's complement is TWO distinct procedures — one to store a negative number, one to read a stored pattern back. Exams love mixing them up. We keep them apart with two cards.

ENCODE — turn −N into its stored bits

① Write the binary of +N.
② Flip ALL bits (one's complement).
③ Add 1 (two's complement) → this is what memory stores.

DECODE — turn a stored pattern into a signed decimal

① Confirm MSB = 1 (it IS negative).
② Subtract 1.
③ Flip ALL bits.
④ Convert to decimal, attach a minus sign.

S4 · WATCH ONE ENCODE — STORING −5 IN THE 4-BIT tap TYPE

ENCODE −5 · FLIP & ADD
STEP 1
+5 = 0101plain binary of the magnitude first
STEP 2
flip every bit → 1010one's complement: 1→0, 0→1, no exceptions
STEP 3
1010 + 1 = 1011binary addition, carries and all — this pattern is what memory stores for −5
−5 lives in memory as 1011. Note its MSB is 1 — the amber flag is honest. ✓

S5 · EXAMPLE 1 — DECODE 1000 · THE FAMOUS TRAP

DECODE 1000 · PREDICT BEFORE EACH PRESS
CHECK
MSB = 1 → negativedecode dance is mandatory — no direct conversion allowed
−1
1000 − 1 = 0111binary subtraction with borrows
FLIP
0111 → 1000…wait. We're back where we started?!
READ
the only 1-bit sits at 2³ → magnitude 8, attach sign → −8
1000 = −8. Yes, this one really does map to itself — that's NOT a mistake.
The self-mapping trap — flagged on purpose

1000 is the MOST NEGATIVE value of a 4-bit type, and the boundary value of a signed range is always its own two's complement. Students hit this, assume they made an arithmetic slip, and redo it three times. You didn't slip. It cycles. Move on with confidence.

EXAMPLE 2 — DECODE 1001 · THE CLEAN CASE

DECODE 1001 · SAME FOUR STEPS
CHECK
MSB = 1 → negative
−1
1001 − 1 = 1000
FLIP
1000 → 0111
READ
0111 = 2² + 2¹ + 2⁰ = 4 + 2 + 1 = 7 → attach sign → −7
1001 = −7 ✓ — one step inward from the boundary, one step up from −8.

TOPIC 1 · PART 5 · THE PROOF, THE CHALLENGE, THE TRAPS

The moment the formula stops being memorized.

S6 · EXAMPLE 3 — THE REGISTER AND THE ALGEBRA AGREE

WHAT THE 16 PATTERNS SHOWED

8 blue patterns 0000–0111 → 0 to 7
8 amber patterns 1000–1111 → −8 to −1

Examples 1 & 2 decoded the deepest two: 1000 = −8 (boundary) and 1001 = −7.

WHAT THE FORMULA SAYS FOR n = 4

min = −2³ = −8 ✓ matches the deepest amber
max = 2³ − 1 = 7 ✓ matches the highest blue

Range of tap: −8 to 7. You didn't memorize it. You just proved it.

"8 combinations were negative" ↔ "−2^(n−1)". The register and the algebra are the same sentence in two alphabets.

S7 · EXAMPLE 4 — YOUR TURN: THE REAL byte · n = 8 · TYPE YOUR PREDICTION

CHALLENGEApply the formula to Java's real byte (n = 8) — type BOTH boundary values, then check against Byte.MIN_VALUE / Byte.MAX_VALUE.

min =  max =

Work it in the notebook first: min = −2⁷, max = 2⁷ − 1.

MISCONCEPTION PATROL · THE THREE WRONG SENTENCES (T1)

"The left side of the range should also be 2^(n−1), without the minus… or 2^n − 1 like the max."

Only positive-only encodings top out at 2^n − 1. The signed negative side holds ONE extra value (−2^(n−1)) because the boundary pattern is its own two's complement — the single most confused point in this topic.

WRONG ✗

"1000 stayed the same after two's complement — I must have made a mistake."

Confirmed correct in Example 1: the boundary value of every signed range maps to itself. No mistake.

NOT A MISTAKE

"I can read a pattern as plain binary even when MSB = 1."

That produces a wildly wrong LARGE POSITIVE value (1000 read raw = +8, truth = −8). Decoding is MANDATORY when MSB = 1 — and this exact trap returns in Topic 3's right-shift on negatives. Remember it.

FORBIDDEN ✗

PRACTICE · T1Notebook out — four questions, solutions locked below.

  1. A hypothetical type allocates 6 bits. State its range using the formula, then verify by writing the boundary bit patterns and decoding them manually.
  2. Decode the 8-bit pattern 11110110 with the two's complement procedure (MSB check → subtract 1 → flip → convert → sign).
  3. True/False with justification: "Every n-bit signed range contains exactly one more negative number than positive number (excluding zero)."
  4. A short is 16 bits. Without looking it up, derive its min/max from the formula and state both values.

Attempt all four on paper first — the derivation IS the learning.

T1 SOLUTIONS
  • Q1n = 6 → min = −2⁵ = −32, max = 2⁵ − 1 = +31. Boundaries: 100000 decodes to −32 (self-mapping boundary again!), 011111 = 16+8+4+2+1 = 31. ✓
  • Q211110110: MSB = 1 → negative. Subtract 1 → 11110101. Flip → 00001010 = 8 + 2 = 10. Attach sign → −10.
  • Q3True. Negatives: −1 … −2^(n−1) = 2^(n−1) values. Positives: 1 … 2^(n−1) − 1 = 2^(n−1) − 1 values. Exactly one more negative — the self-mapping boundary is the extra one.
  • Q4n = 16 → min = −2¹⁵ = −32,768, max = 2¹⁵ − 1 = +32,767 — Java's documented short range.

TOPIC 2 · PART 6 · BITWISE OR · AND · XOR

Three tiny tables run the whole show.

A bitwise operator takes two individual bits and produces ONE output bit by a fixed rule. Applied to full numbers, the rule runs independently at every bit position — rightmost with rightmost, next with next — with ZERO interaction between columns.

THE THREE TRUTH TABLES — PINNED FOR THE REST OF THE TOPIC

OR · a | bany 1 wins
ABA|B
000
011
101
111
0 only when BOTH are 0.
AND · a & bany 0 kills
ABA&B
000
010
100
111
1 only when BOTH are 1.
XOR · a ^ bdifference detector
ABA^B
000
011
101
110
Same bits → 0 · different bits → 1.

Fastest recall hooks: OR — "any 1 wins" · AND — "any 0 kills" · XOR — "same → 0, different → 1".

Standing note: | & are NOT || &&

Bitwise operators act on every bit position independently across the full binary representation. Logical operators (||, &&) act on a single true/false outcome. One character of difference, two completely different machines.

EXAMPLE 1 · THE BASELINE PAIR — a = 5, b = 9 · COLUMN BY COLUMN, PREDICT EACH BIT

2⁷2⁶2⁵2⁴2⁰
a = 500000101zero-padded to 8 bits — always
b = 900001001
a | b00001101= 8+4+1 = 13
a & b00000001= 1 — only 2⁰ had 1&1
a ^ b00001100= 8+4 = 12 — 2⁰ was SAME so 0

In class: pick the output bit for each column BEFORE it lands. Green if you called it, red column if you didn't — then re-derive that one column from the table.

EXAMPLES 2 & 3 — SAME MACHINE, NEW NUMBERS

EXAMPLE 2 · a = 12, b = 10

a = 12 00001100
b = 10 00001010
a | b = 00001110 = 14
a & b = 00001000 = 8
a ^ b = 00000110 = 6

EXAMPLE 3 · a = 7, b = 3

a = 7 00000111
b = 3 00000011
a | b = 00000111 = 7 — b's bits were already inside a!
a & b = 00000011 = 3 — the overlap IS b
a ^ b = 00000100 = 4 — only where they differ

EXAMPLE 4 — a = 15, b = 6 · THE "ALL-ONES" PATTERN REVEALS ITSELF

a = 1500001111all four low bits set
b = 600000110
a | b00001111= 15 — every set bit survives
a & b00000110= 6 — b returned unchanged!
a ^ b00001001= 8+1 = 9

Pattern banner — not a coincidence: OR-ing with all 1s returns all 1s. AND-ing with all 1s returns the other operand unchanged. Within this 4-bit-low width, 15 = 1111 acts as the identity for AND — worth flagging, because interviews use it as a mask trick.

EXAMPLE 5 — a = 20, b = 5 · THE ANTI-GUESSING TRAP

a = 200001010000010100
b = 50000010100000101
a | b00010101= 16+4+1 = 21 · NOT 25!
a & b00000100= 4
a ^ b00010001= 16+1 = 17

20 + 5 = 25 sits close enough to 21 to hide a guesser. The result is NEVER computed from decimals — only bit by bit, then converted. That's why this pair is here.

EXAMPLE 6 — CODE VERIFICATION · PREDICT ALL THREE LINES BEFORE THE REVEAL

SAVE AS · EXACT NAME, EXACT FOLDER · NEW u1-addon FOLDER C:\Users\<you>\Desktop\java-practice\u1-addon\BitwiseCheck.java
BitwiseCheck.java
1public class BitwiseCheck
2{
3 public static void main(String[] args)
4 {
5 byte a = 5, b = 9;
6 System.out.println(a | b); // hand answer said 13
7 System.out.println(a & b); // hand answer said 1
8 System.out.println(a ^ b); // hand answer said 12
9 }
10}
OUTPUT · THE MACHINE AGREES
> 13
> 1
> 12
All three match Example 1's hand-worked columns. Homework: extend this same file to verify Examples 2–5 yourself — type it, don't read it.
The hand column table is the answer; the code is only the witness. In the exam you get no compiler — the columns are the skill.
Desktop\java-practice\u1-addon\ save BitwiseCheck.java javac BitwiseCheck.java BitwiseCheck.class appears java BitwiseCheck
The class-02 round trip, unchanged: every runnable file on this page follows this exact sequence in the SAME u1-addon folder — save → javac File.java (compile) → java File (run, no .java). No program today reads keyboard input, so no sample input is needed — outputs are fully determined by the code you type.

MISCONCEPTION PATROL · T2

"| and & are just || and && written short."

Bitwise = per-bit across the whole representation. Logical = one true/false. Different machines.

WRONG ✗

"101 vs 1001 — I'll just line them up from the left."

Without zero-padding to EQUAL width, every column after the first is misaligned. Fixed-width padding first, always — the column table enforces it by design.

PAD FIRST ✗

"20 | 5 should be around 25 — OR sort of adds them."

Example 5 exists to kill this: the answer is 21, not 25. No decimal arithmetic is ever involved — only bits.

NO ADDING ✗

PRACTICE · T2Four questions — full bit tables in the notebook.

  1. Compute a | b, a & b, a ^ b for a = 11, b = 6 — show the full bit table.
  2. WITHOUT computing bit-by-bit: will a & b be smaller than, larger than, or equal to both a and b? Justify from the truth table, then verify with a = 25, b = 18.
  3. True/False with justification: "a ^ a always equals 0, for any value of a."
  4. A student claims 12 | 5 = 17 because 12 + 5 = 17. Say exactly why the reasoning is wrong, then compute the correct answer.

Columns on paper first — the table is the technique.

T2 SOLUTIONS
  • Q111 = 00001011, 6 = 00000110 → OR = 00001111 = 15 · AND = 00000010 = 2 · XOR = 00001101 = 13.
  • Q2AND can only KEEP a 1 where BOTH have 1 — it can never create one. So a & b ≤ a and ≤ b, always. Check: 25 = 00011001, 18 = 00010010 → AND = 00010000 = 16 ≤ both. ✓
  • Q3True. Every column compares a bit with ITSELF — always "same" — and XOR gives 0 for same bits. All columns 0 → result 0.
  • Q4OR never adds — it works column-wise with no carries. 12 = 00001100, 5 = 00000101 → OR = 00001101 = 13, not 17. (It LOOKS like addition here only because no columns overlap — 12 & 5 = 0. With overlap, e.g. Example 5, the illusion breaks.)

TOPIC 3 · PART 7 · SHIFT OPERATORS

Bits slide. The question is only: what fills the hole?

All three shift operators slide every bit sideways and discard what falls off the edge. The ENTIRE difference between them is the filler bit that enters the vacated end — and that one bit decides whether the sign survives.

LEFT SHIFT <<RIGHT SHIFT >>TRIPLE RIGHT SHIFT >>>
Also known assigned / arithmeticunsigned / logical
Filler bitalways 0copy of the original MSB (sign-preserving)always 0 — even for negatives
Meaning× 2^kfloor-divide by 2^k, sign keptsign DESTROYED on negatives → large positive
On positives× 2^kidentical results
On negatives× 2^kstays negativebecomes large positive
In Pythonexistsexistsnot supported (no fixed-width type)
Naming trap: "triple right shift" does NOT shift three times

The "triple" refers to the three-character symbol >>>, not a shift count. a >>> 1 shifts exactly once. A naming trap, not a logic trap — but it costs marks every year.

LIVE REGISTERS · ONE PRESS, THREE MACHINES — WATCH THE FILLERS DIVERGE IN MOTION

ANIMATED · T3All three registers hold the SAME stored −5. Press SLIDE ONCE and watch every bit physically slide, the edge bit fall off, and each machine's own filler drop into the hole — blue 0, amber sign-copy, forced blue 0.

<< · LEFT SHIFT
filler enters on the RIGHT · always 0

Every slide doubles the value — sign and all.

>> · SIGNED RIGHT
filler = copy of the old MSB

The amber 1 keeps sliding in — the sign SURVIVES.

>>> · UNSIGNED RIGHT
filler forced to 0 — even here

One blue 0 in the sign seat — negative DESTROYED.

SLIDES: 0

Same input, three destinies — press SLIDE ONCE to start the race.

EXAMPLES 1–3 · LEFT SHIFT — WATCH 5 DOUBLE, DOUBLE, DOUBLE

5 << 1 · 5 << 2 · 5 << 3 — ZERO-FILLER SLIDES IN FROM THE RIGHT
START
5 = 00000101
<< 1
00001010 = 8+2 = 10= 5 × 2 — one zero entered on the right
<< 2
00010100 = 16+4 = 20= 5 × 2² = 5 × 4
<< 3
00101000 = 32+8 = 40= 5 × 2³ = 5 × 8 — the pattern holds for EVERY count
Left shift by k = multiply by 2^k. Filler is always blue 0.

EXAMPLE 4 · RIGHT SHIFT ON A POSITIVE — 5 >> 1 AND 5 >> 2

MSB = 0 → THE FILLER IS 0 · NO DECODE NEEDED
START
5 = 00000101, MSB = 0 (positive) → filler is 0
>> 1
00000010 = 2floor of 5 ÷ 2
>> 2
00000001 = 1floor of 5 ÷ 4
MSB stayed 0 throughout → no two's-complement undo. The decode tracer stays collapsed — that step is CONDITIONAL, not automatic.

TOPIC 3 · PART 8 · NEGATIVE OPERANDS — WHERE MARKS ARE WON

−5 >> 1 and −5 >>> 1 — same input, wildly different worlds.

These two walkthroughs carry the most misconception risk on the whole page. In class: predict the filler bit before every press. The full encode → shift → decode dance from Topic 1 comes back exactly as promised.

EXAMPLE 5 · −5 >> 1 — THE FULL THREE-STEP TRACE

ENCODE → SHIFT → DECODE · NOTHING SKIPPED
ENCODE
+5 = 00000101 → flip → 11111010 → +1 → 11111011this is what memory stores for −5 (Topic 1's dance, unchanged)
SHIFT
11111101 ← filler = original MSB = 1 (amber!)11111011 >> 1 → 11111101 — sign-preserving by construction
DECODE
MSB = 1 → subtract 1 → 11111100 → flip → 00000011 = 2+1 = 3the undo is NOT optional when MSB = 1
RESULT
−5 >> 1 = −3
Consistent with "shift ≈ floor-divide": −5 ÷ 2 floors to −3, NOT −2. The bits and the maths agree.

EXAMPLE 6 · 5 >>> 1 — ON POSITIVES, >>> IS JUST >>

SAME AS EXAMPLE 4'S FIRST LINE
>>> 1
5 = 0000010100000010 = 2MSB was 0, so the 0-filler matches what >> would have used anyway
For positive numbers, >> and >>> ALWAYS agree. They only diverge on negatives — next.

EXAMPLE 7 · −5 >>> 1 — THE OPERATOR'S DEFINING CASE · WATCH THE FILLERS DIVERGE

>> · FILLER = ORIGINAL MSB (1)

11111011 stored −5 (from Ex 5)
11111101 amber 1 slid in
decodes to −3 sign preserved

>>> · FILLER = ALWAYS 0

11111011 same stored −5
01111101 blue 0 slid in — THE divergence
MSB now 0 → read DIRECTLY: 64+32+16+8+4+1 = 125 no decode — it's positive now

Same input: >> gave −3, >>> gave +125. One filler bit destroyed the sign. THAT is why >>> is called unsigned.

Shown at 8-bit width for teaching clarity. At Java's real 32-bit int width, -5 >>> 1 becomes a very large positive number close to 2³¹ (2147483645) — the mechanism is identical, only the width changes.

EXAMPLE 8 · THE FLIP OPERATOR ~ (BITWISE COMPLEMENT) — ALL BITS SWAP 0↔1 AT ONCE, BOTH DIRECTIONS

~2 — POSITIVE GOES IN

2 = 00000010
flip ALL → 11111101 simultaneous, not one-by-one — this is NOT a shift
MSB = 1 → decode: −1 → 11111100 → flip → 00000011 = 3 → −3
shortcut: ~n = −(n+1) = −(2+1) = −3

~(−2) — NEGATIVE GOES IN

−2 stored as 11111110
flip ALL → 00000001
MSB = 0 → direct conversion → 1
shortcut: −(−2+1) = −(−1) = 1

~ is NOT unary minus: ~2 = −3, but −2 = −2. The FLIP swaps EVERY bit, it never touches a "sign flag". The shortcut ~n = −(n+1) works in both directions — verify once by hand, then trust it.

FLIP vs NEGATION — say the two words precisely, they are DIFFERENT operations

FLIP = the ~ operator (bitwise complement): every bit swaps — all 0s become 1s and all 1s become 0s — and then you STOP. Result: ~n = −(n+1), so ~2 = −3.
NEGATION = unary minus -n (two's complement): FLIP every bit and then add 1. Result: -2 = −2’s stored pattern, i.e. -n = ~n + 1, so -2 = ~2 + 1 = −3 + 1 = −2.
One extra "+1" is the entire difference — flip stops after swapping the bits; negation swaps AND adds 1. In the bit machine below, the purple button does the FLIP only, and the red button performs the full NEGATE showing both steps separately. Drive both on the same number and watch them land one apart.

THE BIT MACHINE · DRIVE EVERY OPERATOR YOURSELF — PREDICT, PRESS, VERIFY

8-BIT REGISTER · PICK A NUMBER, PICK AN OPERATOR, WATCH THE BITS OBEY
1 · LOAD A NUMBER
2 · FIRE AN OPERATOR — SAY THE ANSWER OUT LOUD FIRST
BITS: VALUE: load a number

Load a number to begin. MSB seat is marked — when a 1 sits there, the decode dance from Topic 1 is mandatory.

⚠ WIDTH WARNING — this register is 8-bit for teaching clarity; a real Java int is 32-bit. For <<, >>, ~ and NEGATE the small-width answer matches Java exactly (on these small numbers). For >>> on a NEGATIVE it does NOT: the mechanism is identical but Java has 24 more bits, so e.g. -9 >>> 2 = 61 here but 1073741821 in real Java. The log line always shows BOTH — quote the 32-bit one in exams.

MISCONCEPTION PATROL · T3

"After shifting a negative, I'll just convert the bits to decimal."

The Topic-1 trap resurfaces exactly here, as promised. HARD RULE: if the post-shift MSB is 1, the two's-complement undo is NOT optional.

HARD RULE ✗

">> and >>> always give different answers."

They diverge ONLY on negatives. Examples 4 and 6 produced identical results on +5 — deliberately shown to stop the over-generalization.

ONLY ON NEGATIVES

"Triple right shift = shift three times."

Three CHARACTERS in the symbol, not three shifts. a >>> 1 shifts once.

NAMING TRAP ✗

"~ just flips the sign, like writing a minus."

~2 = −3 while −2 = −2 — different values, one keystroke apart. FLIP (~) swaps every bit and stops; NEGATION (-n) swaps every bit AND adds 1. -n = ~n + 1, always.

NOT MINUS ✗

"Flip and negation are the same thing — both 'flip the bits'."

They differ by exactly +1. FLIP: ~5 = −6 (swap all bits, stop). NEGATION: -5 (swap all bits, then add 1). If your two answers are one apart, you used the wrong word.

OFF BY ONE ✗

PRACTICE · T3Five questions — Q5 is the checkpoint before Topic 4.

  1. Compute 9 << 2 by hand, then verify it equals 9 × 4.
  2. Compute -9 >> 1 with the FULL two's-complement decode shown at every step.
  3. Compute -9 >>> 1 at 8-bit width, explain in ONE sentence why it differs from Q2's answer — then state what real 32-bit Java prints for -9 >>> 1.
  4. Using ONLY the shortcut (no bit-flipping), compute ~7 and ~(-7) — then verify ~7 by flipping bits manually.
  5. True/False with justification: "For any positive integer a, a >> 1 and a >>> 1 always produce the same result."

Every step on paper — especially Q2's decode.

T3 SOLUTIONS
  • Q19 = 00001001 → << 2 → 00100100 = 32 + 4 = 36 = 9 × 4 ✓
  • Q2Encode −9: +9 = 00001001 → flip 11110110 → +1 11110111. Shift (filler = 1): 11111011. Decode: −1 → 11111010 → flip 00000101 = 5 → −5. (Check: −9 ÷ 2 floors to −5 ✓)
  • Q311110111 >>> 1 → 01111011 = 64+32+16+8+2+1 = 123 at 8-bit width. It differs because >>> forced a 0-filler, so the MSB became 0 and the sign was destroyed. Real 32-bit Java: -9 >>> 1 = 2147483643 (and -9 >>> 2 = 1073741821) — same mechanism, 32-bit width; THIS is the number an exam expects.
  • Q4~7 = −(7+1) = −8 · ~(−7) = −(−7+1) = 6. Manual check of ~7: 00000111 → flip 11111000 → MSB 1 → −1 11110111 → flip 00001000 = 8 → −8 ✓
  • Q5True. A positive number's MSB is 0, so >>'s "copy the MSB" filler IS 0 — identical to >>>'s forced 0. Checkpoint passed → Topic 4 unlocked.

TOPIC 4 · PART 9 · VALUE vs REFERENCE — THE VALUE HALF

What does = actually copy?

New cluster, fresh start — no bits required. One innocent symbol, two completely different behaviours: on a primitive, = copies the value; on an object variable, it copies the address. Getting this wrong is how programs silently corrupt each other's data.

The photocopy analogy — VALUE types

Assigning a primitive is photocopying a page of notes. Once the copy is made, scribbling on the photocopy does NOTHING to the original — two physically separate pages that merely started out identical.

The many-names analogy — REFERENCE types

One person can carry many names — the birth-certificate name, a childhood nickname, what friends call them. If that person changes their hairstyle, EVERY name now refers to a person with the new hairstyle — because there was only ever ONE person.

EXAMPLE 1 · int a = 100 — WATCH THE VALUE GET "PRINTED", NOT LINKED

BOX a

a = 100 int a = 100;
a still = 100 nobody ever wrote into a's box — HOW could it change?

BOX b

b = ? int b; — its own separate box, empty
b = 100 b = a; → a's CONTENT is photocopied in. No arrow, no link — a copy.
b = 2000 b = 2000; → only THIS box re-renders

println(a) → 100 · println(b) → 2000. Two independent boxes. That's the entire value-type story.

EXAMPLES 2 & 3 · SAME RULE, NEW NUMBERS — AND NOT JUST FOR int

EXAMPLE 2 · int x, y

x = 50 int x = 50;
y = 50 int y = x; — independent copy
y = 999 y = 999;

println(x) → 50 · println(y) → 999

EXAMPLE 3 · float p, q — the rule is NOT int-specific

p = 3.5f float p = 3.5f;
q = 3.5f float q = p;
q = 9.9f q = 9.9f;

println(p) → 3.5 · println(q) → 9.9 — every primitive behaves this way: int, float, char, boolean…

TOPIC 4 · PART 10 · THE REFERENCE HALF — ONE OBJECT, MANY NAMES

b was the only one we touched. a changed anyway.

Now the same = on a class type. A variable of a class type NEVER holds the object — it holds the object's address. Copy the variable, and you copy the address: two names, one object. Examples 4→8 build the full proof on one Car.

EXAMPLES 4 & 5 · CREATE THE CAR — DEFAULTS FIRST, VALUES SECOND

SAVE AS · ONE FILE · PARTS 1 + 2 TOGETHER C:\Users\<you>\Desktop\java-practice\u1-addon\CarShare.java — compile: javac CarShare.java · run: java CarShare
CarShare.java · PART 1
1class Car
2{
3 String name;
4 float mileage;
5 int cost;
6}
7// ...inside main:
8Car a = new Car();
9System.out.println(a.name);
10System.out.println(a.mileage);
11System.out.println(a.cost);
12a.name = "BMW";
13a.mileage = 5.5f;
14a.cost = 75;
15System.out.println(a.name + " " + a.mileage + " " + a.cost);
OUTPUT · DEFAULTS, THEN VALUES
> null
> 0.0
> 0
> BMW 5.5 75
Example 4: the JVM filled every field with a type default BEFORE we touched it — String → null, float → 0.0, int → 0. Example 5: our values overwrite the defaults through reference a. (Topic 5 explains WHERE this happens.)
Grey defaults are a gift for instance variables ONLY — hold that thought until the memory model.

EXAMPLES 6 & 7 · THE SECOND NAME — AND THE PROOF

CarShare.java · PART 2
16Car b; // reference ONLY — no new, NO object created
17b = a; // copies the ADDRESS — b now names the SAME car
18System.out.println(b.name + " " + b.mileage + " " + b.cost);
19b.name = "Tata";
20b.mileage = 15.8f;
21b.cost = 13;
22System.out.println(b.name + " " + b.mileage + " " + b.cost);
23// the critical check — read through the FIRST name:
24System.out.println(a.name + " " + a.mileage + " " + a.cost);
OUTPUT · PREDICT LINE 24 BEFORE PRESSING
> BMW 5.5 75
> Tata 15.8 13
> Tata 15.8 13
Line 24 is THE proof: a was never directly modified, yet its printed values changed — because a and b were always the SAME object. Not "two objects that happen to be equal." One object, two names.
Example 6's quiet bombshell: Car b; created NO object — no constructor ran, no memory for fields was allocated. Only new creates objects. A reference alone is an empty name tag.

EXAMPLE 8 · A THIRD NAME — THE PATTERN GENERALIZES · WATCH THE PURPLE PULSE

REFERENCES LANE (names)

a → addr 1000 the original name
b → addr 1000 from b = a
c → addr 1000 Car c = a; — a third name, same address
all three arrows land on ONE bubble

OBJECTS LANE (the one car)

Car @ 1000 — THE only object
name"Tata"
mileage15.8
cost13 → 999 (c.cost = 999)

println(a.cost) → 999 · println(b.cost) → 999 · println(c.cost) → 999. ANY number of references can share one object; a change through any one is visible through all.

Purple pulse = "same object, many references" — the purple returns in Topic 7 for the static zone, where sharing becomes official.

Value or address? The number alone can never tell you

The literal 1000 is meaningless in isolation. Held by an int, it's a value. Held by a reference, it's an address pointing at an object. The meaning lives in the variable's TYPE, never in the number itself.

MISCONCEPTION PATROL · T4

"= always makes an independent copy — objects included."

For primitives yes; for objects, = copies the ADDRESS. That contrast is the entire topic.

WRONG ✗

"a and b are two separate objects that currently hold equal values."

Example 7 breaks this: a was never touched, yet a's output changed. There was only ever one object.

ONE OBJECT ✗

"Car b; creates a new Car."

No object exists without new — no constructor, no field memory. Just an empty name tag. (Topic 5 shows exactly where that tag lives.)

NO new, NO OBJECT

"1000 is obviously a value / obviously an address."

Depends ENTIRELY on the holding variable's kind — int-type or reference-type. Never on the number.

DEPENDS ✗

PRACTICE · T4Four questions — draw the boxes and arrows for each.

  1. int p = 7; int q = p; q = 42; — final values of p and q? Explain in ONE sentence why.
  2. Given class Point { int x; int y; } and Point m = new Point(); m.x = 5; m.y = 10; Point n = m; n.x = 99; — what is m.x? Explain with "one object, many references".
  3. True/False with justification: "Car b; by itself creates a new Car object in memory."
  4. References p, q, r all point to the same Employee. A change is made to p.salary — what happens to q.salary and r.salary? Justify via what = copies for reference types.

Boxes for values, arrows for references — always draw before answering.

T4 SOLUTIONS
  • Q1p = 7, q = 42. q got an independent PHOTOCOPY of p's value; overwriting the copy never touches the original.
  • Q2m.x = 99. n = m copied the address — m and n are two names for ONE Point, so the write through n is visible through m.
  • Q3False. Only new triggers object creation. Car b; makes an empty reference — no constructor call, no field memory.
  • Q4Both q.salary and r.salary show the new value instantly — = copied the same address into all three, so all three read the one shared object.

TOPIC 5 · PART 11 · THE JAVA MEMORY MODEL — WHERE EVERYTHING ACTUALLY LIVES

Your program can't run from the hard disk. Ever.

Topic 4 kept saying "the object lives at an address" — but WHERE? Time to name the rooms. A saved .java file on disk is just text at rest; the moment Java loads your program into RAM, it carves out one dedicated region — the Java Runtime Environment (JRE) — and splits it into four segments. Every variable you will ever write lives in exactly one of them.

FROM DISK TO RAM — THE LOADING STORY, PIECE BY PIECE

HARD DISK (storage — nothing runs here)

Demo.java file name matches the class holding main
execute here? ✗ a program CANNOT run directly from disk

RAM (the only place code runs)

program loaded ▸ copied from disk into RAM to execute
JRE region created one dedicated block, made the moment loading happens
…and split into FOUR segments revealed below
This is why "the object is at address 1000" made sense in Topic 4 — addresses are RAM locations inside this JRE region. Now we name the four neighbourhoods.

THE FOUR SEGMENTS — PINNED FOR THE REST OF THE CLASS (T5 → T6 → T7 ALL LIVE HERE)

CODE SEGMENT

The compiled program instructions themselves — your methods' bytecode sits here, read-only, while it runs.

STATIC SEGMENT

Static members live here — one shared copy per class. We flag it now and give it its own full topic (T7, the bonus).

HEAP SEGMENT

Objects — and EVERY instance variable belonging to them. When new runs, the memory comes from here.

STACK SEGMENT

Method calls in progress, local variables, and reference variables. Yes — references live HERE, not next to their object.

Topic 4's "references lane / objects lane" picture was this all along: the references lane IS the stack, the objects lane IS the heap. Same diagram, official names.

THE ONE RULE THAT CLASSIFIES EVERY VARIABLE — LOCATION, NOT NAME, NOT TYPE

INSTANCE VARIABLE

Declared directly inside a class, NOT inside any method. Allocated on the Heap. The JVM auto-fills it with a type default (null / 0 / 0.0 / false) the moment the object is created.

LOCAL VARIABLE

Declared directly inside a method. Allocated on the Stack. Gets NO default value — read it before assigning and the compiler refuses to build your program at all.

The test is purely visual/structural. A variable's name or data type NEVER decides its classification — only where the declaration physically sits. And since every Java line lives inside some class, "inside a method" always also means "inside a class" — the distinguishing question is specifically: is it inside a METHOD body or not?

EXAMPLE 1 · THE CLASSIFICATION PUZZLE — INSTANCE OR LOCAL?

FOUR BARE DECLARATIONS · NO CONTEXT GIVEN
CODEint a;  float b;  char c;  boolean d;
ASKInstance or local? Decide before pressing.
The only honest answer: "CANNOT SAY — not enough information." The declaration alone carries zero classification info. The SAME four lines could be either, depending entirely on what surrounds them. Examples 2 and 3 place these exact variables in each context to settle it.

EXAMPLE 2 · THE FULL DOG TRACE — CODE FIRST, THEN THE MEMORY MOVIE

SAVE AS · TWO CLASSES, ONE FILE · RUN THE ONE WITH main C:\Users\<you>\Desktop\java-practice\u1-addon\Dog.java — compile: javac Dog.java · run: java Demo (main lives in Demo!)
Dog.java · THE INSTANCE-VARIABLE PROOF
1class Dog
2{
3 String name;
4 String breed;
5 int cost;
6}
7class Demo
8{
9 public static void main(String[] args)
10 {
11 Dog d = new Dog();
12 System.out.println(d.name);
13 System.out.println(d.breed);
14 System.out.println(d.cost);
15 d.name = "Scooby";
16 d.breed = "Pug";
17 d.cost = 10000;
18 System.out.println(d.name + " " + d.breed + " " + d.cost);
19 }
20}
OUTPUT · PREDICT LINES 12–14 FIRST
> null
> null
> 0
> Scooby Pug 10000
The three defaults printed BEFORE we assigned anything — the JVM filled them in. Then lines 15–17 overwrite each default through the same reference d — nothing new is created, the same heap object simply gets its fields updated. Now watch WHERE each step happened ↓
name, breed, cost sit directly inside class Dog, not inside any method → instance variables by the location rule.

THE 7-STEP MEMORY MOVIE — EXACTLY WHAT new Dog() DID

LINE 11 · Dog d = new Dog(); — FRAME BY FRAME
1main is always the FIRST method to execute in a Java program — it's already running on the stack.
2Control reaches new Dog(). The new keyword activates the JVM's object-creation process.
3The JVM locates class Dog, finds its instance variables (name, breed, cost), and allocates memory for all three on the HEAP segment.
4Before control returns, the JVM fills each with its type default: name = null, breed = null, cost = 0. This filling step is called initialization.
5Control moves to the LEFT side of the =. Reference d is created — references are NEVER on the heap or static segment; they always live on the STACK segment.
6d receives the heap address of the new object (conceptually, 1000) — d now refers to that object.
7Printing d.name, d.breed, d.cost confirms the step-4 defaults: null null 0.

HEAP · addr 1000

name null · default
breed null · default
cost 0 · default
name = "Scooby" overwritten via d
breed = "Pug" overwritten via d
cost = 10000 overwritten via d

STACK · main's frame

d → 1000 reference · points into the heap
the arrow crosses segments: stack → heap
Grey = JVM defaults, green = your values. The overwrite (lines 15–17) changed the heap fields IN PLACE — d itself never moved, never changed, still holds 1000.

TOPIC 5 · PART 12 · LOCAL VARIABLES — NO DEFAULTS, NO MERCY

The compiler would rather kill the build than guess a value.

Instance variables got free defaults. Local variables get nothing — and it's not a runtime surprise, it's a compile-time refusal. Same four variables as Example 1, now placed inside main:

EXAMPLE 3 · FOUR LOCALS, FOUR COMPILE ERRORS — ONE AT A TIME

LocalTrap.java · WILL NOT COMPILE
1public static void main(String[] args)
2{
3 int a;
4 float b;
5 boolean c;
6 double d;
7 System.out.println(a);
8 System.out.println(b);
9 System.out.println(c);
10 System.out.println(d);
11}
COMPILER · PREDICT: 0? 0.0? false? OR…
> error: variable a might not have been initialized
> error: variable b might not have been initialized
> error: variable c might not have been initialized
> error: variable d might not have been initialized
ALL FOUR fail — not just one. This is the direct, observable proof that locals receive NO default. The JVM will not silently hand you 0 / 0.0 / false the way it did for Dog's fields.
Compile error ≠ runtime error: the program never even becomes runnable. The compiler blocks the build.

THE STACK VIEW — RED HATCHING MEANS "NO VALUE EXISTS", NOT "VALUE IS ZERO"

STACK · main's frame · BEFORE THE FIX

a declared · UNASSIGNED · unprintable
b declared · UNASSIGNED · unprintable
c declared · UNASSIGNED · unprintable
d declared · UNASSIGNED · unprintable
Red hatching is deliberately a DIFFERENT visual from the grey "default" boxes in the Dog trace — never confuse "no default exists" (local, compile error) with "has a default of zero" (instance, prints fine).

The broken state: System.out.println(a); with a unassigned → variable a might not have been initialized. The read is the crime — declaring alone is legal.

The fix — assign before reading: a = 99; b = 99.99f; c = true; d = 100.99; — note the f suffix on 99.99f: a bare 99.99 is treated as a double, causing a type mismatch against a float variable.

THE FIXED FILE — SAME FOUR LOCALS, NOW PRINTABLE

LocalTrap.java · FIXED
7 a = 99;
8 b = 99.99f; // the f suffix — bare 99.99 is a double
9 c = true;
10 d = 100.99;
11 System.out.println(a);
12 System.out.println(b);
13 System.out.println(c);
14 System.out.println(d);
OUTPUT · NOW IT COMPILES
> 99
> 99.99
> true
> 100.99
Each hatched stack box converts to a solid, printable one only when YOUR assignment lands. Explicit initialization before use — the programmer's job, never the JVM's, for locals.

EXAMPLE 4 · THE PUZZLE RESOLVED — SAME FOUR LINES, OPPOSITE VERDICTS

DIRECTLY INSIDE A CLASS, NO METHOD

class Sample { int a; float b; char c; boolean d; }
verdict: INSTANCE ✓ heap · gets defaults on new

DIRECTLY INSIDE A METHOD (main)

public static void main(...) { int a; float b; char c; boolean d; }
verdict: LOCAL ✓ stack · NO defaults · assign before use
Identical declarations, opposite classification — purely because of WHERE each block sits. The cleanest possible proof that the rule is structural, never about name or type.

EXAMPLE 5 · THE RULE GENERALIZES — MEET Book

Book b1 = new Book(); — DEFAULTS BY TYPE
CODEclass Book { String title; String author; double price; }
titleb1.titlenull (String)
authorb1.authornull (String)
priceb1.price0.0 (double — new type, same numeric-default pattern as int's 0)
Not a Dog-only trick: ANY String field defaults to null, ANY numeric field to its zero. The rule is about instance variables as a species, not one example class.

EXAMPLE 6 · THE MIXED-SCOPE TRICK — SAME NAME, BOTH ROLES

SAVE AS · SAME FILE FOR EXAMPLE 6 AND T7'S EXAMPLE 3 — ADD A main THAT CALLS show() C:\Users\<you>\Desktop\java-practice\u1-addon\Counter.java — compile: javac Counter.java · run: java Counter
Counter.java · STRESS TEST FOR NAME-CLASSIFIERS
1class Counter
2{
3 int value; // instance — lives on the HEAP once an object exists
4 void reset()
5 {
6 int value; // local — lives on the STACK, only during this call
7 value = 0;
8 // this local 'value' does NOT touch the instance variable of the same name
9 }
10}
Identical names do not merge or conflict. Each value is judged purely by where it is declared: line 3 sits directly inside the class → instance, heap-allocated. Line 6 sits directly inside a method → local, stack-allocated, temporary — it vanishes when reset() returns. This example exists specifically to break anyone still classifying by NAME instead of by LOCATION.
Foreshadow: T7's bonus adds a third player — static — and re-runs this exact three-way classification game.

MISCONCEPTION PATROL · THE FOUR WRONG SENTENCES (T5)

"I can tell it's an instance variable from its name / its type."

The classification rule is purely about declaration LOCATION. Examples 1, 4 and 6 exist to break this — Example 6 uses the very same name in both roles.

WRONG ✗

"Locals get defaults too — printing an unassigned int just gives 0."

Example 3 disproves this with an observable COMPILE error on all four variables — not a silent 0/false/null at runtime. The build simply fails.

WRONG ✗

"The reference is stored on the heap, next to its object."

References are ALWAYS created on the Stack, regardless of where the object lives — step 5 of the Dog trace, and the whole point of the cross-segment arrow.

WRONG ✗

"It's declared inside main's class, so it's an instance variable."

The test is about being inside a METHOD body or not — main is itself a method, so anything declared directly inside main is LOCAL, even though main sits inside a class.

WRONG ✗

PRACTICE · T5Five questions — draw the four segments before answering each.

  1. Classify each variable as instance or local, justifying with the location rule only: class Wallet { double balance; void topUp() { double amount; amount = 50; } }
  2. A learner writes int score; System.out.println(score); inside a method and expects 0 to print. What actually happens, and why?
  3. True/False with justification: "An object's instance variables are allocated at the same time as its reference variable, in the same memory segment."
  4. Given class Player { String name; int lives; } and Player p = new Player(); — state the exact default of each field immediately after this line, before any further code.
  5. Explain in one or two sentences why main's local variables can share a name with a class's instance variables without any conflict.

Segment sketch first — code / static / heap / stack — then place every variable.

T5 SOLUTIONS
  • Q1balance — directly inside the class, not in a method → instance (heap). amount — directly inside topUp()local (stack, no default, but it's assigned before any read, so legal).
  • Q2Compile error: variable score might not have been initialized. Locals have no default-value concept — the compiler blocks the read; the program never runs at all.
  • Q3False twice over: instance variables go on the heap when new runs (right side of =), the reference goes on the stack (left side) — different segments, and steps 3–4 happen before step 5 in the trace.
  • Q4p.name = null (String), p.lives = 0 (int) — filled by the JVM's initialization step the moment the object is created.
  • Q5They live in different segments with different lifetimes: the instance copy sits inside the heap object, the local copy sits in the method's stack frame and dies when the method returns. Classification is by location, so identical names never merge or clash.

TOPIC 6 · PART 13 · RECURSION — THE STACK SEGMENT IN MOTION

A function that calls itself. A stack that grows until it can't.

Recursion is simply a function calling itself — not a special language feature, just an ordinary call where the callee happens to be the caller. But T5's Stack segment now goes DYNAMIC: every call — recursive or not — creates a dedicated stack frame (activation record) holding that call's local variables. Return → frame popped, control drops to the frame below. The stack grows and shrinks freely… but it cannot grow forever. Exceed its memory and you get a StackOverflowError.

EXAMPLE 1 · NO BASE CONDITION — WATCH IT DIE (NOT LEARNER-PACED, BY DESIGN)

Runaway.java · NOTHING EVER STOPS THIS
1static void fun(int n)
2{
3 System.out.println(n);
4 fun(n - 1); // calls itself — with NO condition to ever stop
5}
6// called as: fun(3);
OUTPUT · IT NEVER STOPS PRINTING
> 3
> 2
> 1
> 0
> -1
> -2 …
> Exception in thread "main" java.lang.StackOverflowError
fun(3) → prints 3, calls fun(2) → prints 2, calls fun(1)… then fun(0), fun(−1), fun(−2)… each call stacking a NEW frame. This is not hypothetical — it is exactly what happens if this code is run. The recursive equivalent of an infinite loop, except the "infinite" is eating MEMORY, frame by frame.

THE STACK ZONE DURING THE RUNAWAY — FRAMES PILE UNTIL THE ROOM BURSTS

fun(3) · n = 3 frame 1 — printed 3, called fun(2)
fun(2) · n = 2 frame 2 — printed 2, called fun(1)
fun(1) · n = 1 frame 3 — printed 1, called fun(0)
fun(0) · n = 0 frame 4 — printed 0, called fun(−1)
fun(−1) · n = −1 frame 5 — and on, and on…
💥 StackOverflowError the stack segment is OUT of space — program terminated
STACK SEGMENT FLOOR · main's frame sits below
No frame ever popped — nothing in the function ever stops the recursion, so frames only stack up (n = −1, −2, −3, …) until the segment's limit. A recursive function without a base condition is, without exception, a bug waiting to happen.

EXAMPLE 2 · THE FIX — A BASE CONDITION, PLACED BEFORE THE CALL

SAVE AS · WRAP IN class Controlled { … } WITH A main THAT CALLS fun(3) C:\Users\<you>\Desktop\java-practice\u1-addon\Controlled.java — compile: javac Controlled.java · run: java Controlled
Controlled.java · THE BASE CONDITION
1static void fun(int n)
2{
3 if (n < 1)
4 {
5 return; // base condition — stop HERE, do NOT recurse further
6 }
7 System.out.println(n);
8 fun(n - 1);
9}
10// called as: fun(3);
OUTPUT · CONTROLLED THIS TIME
> 3
> 2
> 1
3 2 1 — and a clean exit. The check sits BEFORE the recursive call: when n < 1 becomes true, return hands control straight back — no print, no further call. A void return passes back only the flow of execution, no data.
Placement is the whole game: base condition BEFORE the recursive call. Check it after, and the call has already happened — the check is useless.

THE FULL 6-STEP FRAME TRACE — PREDICT AT EVERY FRAME: PRINT, OR POP?

fun(3) WITH BASE CONDITION · GROW TO 4, SHRINK TO 0
1main calls fun(3) → frame created, n = 3. Base condition (3 < 1) false. Print 3. Call fun(2).
2New frame, n = 2. Base false. Print 2. Call fun(1).
3New frame, n = 1. Base false. Print 1. Call fun(0).
4New frame, n = 0. Base condition (0 < 1) TRUEreturn immediately — NO print, NO further call. Frame popped.
5Control returns to the fun(1) frame — no statements remain after its recursive call — popped.
6Back to fun(2) — popped. Back to fun(3) — popped. Back to main. Stack: empty again.
Output 3 2 1. The stack grew from empty to 4 frames deep, then shrank back to empty — exactly the controlled behaviour a base condition exists to produce.
fun(3) · n = 3 printed 3 · waiting on fun(2)
fun(2) · n = 2 printed 2 · waiting on fun(1)
fun(1) · n = 1 printed 1 · waiting on fun(0)
fun(0) · n = 0 base condition TRUE → returns WITHOUT printing ✓
fun(0) popped · then fun(1) · fun(2) · fun(3) reverse order, one at a time
STACK SEGMENT FLOOR · main's frame sits below
Green frame = base condition hit. Note each frame holds its OWN copy of n — four separate n's existed at the peak. That observation becomes Example 6's efficiency argument.

EXAMPLE 3 · SAME MACHINE, NEW FUEL — fun(5)

fun(5) · DOES THE MECHANISM GENERALIZE?
GROWFrames for n = 5, 4, 3, 2, 1 — each prints its value, then recurses.
STOPThe n = 0 frame hits the base condition → returns without printing.
OUT5 4 3 2 1 — the base-condition mechanism works for ANY starting value, not just 3.

TOPIC 6 · PART 14 · RETURN VS BREAK · RECURSION VS ITERATION

break doesn't even compile. And iteration is usually cheaper.

Two exam favourites left: the break trap (a compile-time error, not a style choice) and the honest efficiency comparison the interviewer always asks next.

EXAMPLE 4 · SWAP return FOR break — COMPILE AND SEE

The attempt: if (n < 1) { break; } inside funerror: break outside switch or loop. break is ONLY valid inside a loop or a switch — a function body containing an if is neither. The build dies on the spot.

The only exit: return is the correct way to leave a function early. In a void function, a bare return; hands back only the flow of execution — no data, just control. Toggle the line back to return; and the compile succeeds, exactly as Example 2 showed.

EXAMPLE 5 · THE ITERATIVE EQUIVALENT — SAME OUTPUT, ONE FRAME

SAVE AS · DROP THE LOOP INSIDE main OF class LoopVersion { … } C:\Users\<you>\Desktop\java-practice\u1-addon\LoopVersion.java — compile: javac LoopVersion.java · run: java LoopVersion
LoopVersion.java · NO SELF-CALLS
1for (int i = 3; i >= 1; i--)
2{
3 System.out.println(i);
4}
OUTPUT · IDENTICAL TO EXAMPLE 2
> 3
> 2
> 1
Exact same 3 2 1 — but with a SINGLE stack frame (the containing method's) and a SINGLE variable i updated in place each pass. No repeated calls, no repeated frame creation.

EXAMPLE 6 · THE HONEST SCORECARD — RECURSIVE (EX 2) VS ITERATIVE (EX 5), SAME TASK

RECURSIVE (Example 2)ITERATIVE (Example 5)
Stack frames created4 — one per call: fun(3), fun(2), fun(1), fun(0)1 — the containing method's own frame
Copies of the counting variable4 separate copies of n (one per frame, 4 bytes each = 16 bytes)1 copy of i (4 bytes), reused every iteration
Function calls made40 — just loop iterations within the same call

Both time AND space favour iteration here. The general rule: for any problem solvable both ways, iteration is more efficient. Recursion is never the "more advanced, therefore better" option — it must earn its overhead (Example 8 shows where it does).

EXAMPLE 7 · A SECOND RECURSIVE FUNCTION — THE PATTERN, NOT THE EXAMPLE

SumDown.java · SAME SKELETON, NEW SKIN
1static void sumDown(int n)
2{
3 if (n < 1)
4 {
5 return; // base condition — CHECK FIRST, recurse second
6 }
7 System.out.println("Adding: " + n);
8 sumDown(n - 1);
9}
10// called as: sumDown(4);
OUTPUT · PREDICT ALL FOUR LINES
> Adding: 4
> Adding: 3
> Adding: 2
> Adding: 1
Same structural pattern as Example 2 — only the printed message changed. The base-condition placement rule (check first, recurse second) applies to ANY recursive function, not just fun.

EXAMPLE 8 · WHERE RECURSION EARNS ITS OVERHEAD — THE INTERVIEW LIST

SELF-SIMILAR STRUCTURES

Tree traversal — each subtree is itself a smaller tree. Binary search — each half-range is itself a smaller search. The problem's SHAPE is recursive, so the code that mirrors it is the natural fit.

DIVIDE & CONQUER + DP

Merge sort and quick sort — each half is itself a smaller sort. Dynamic programming (with memoization) — each subproblem is a smaller version of the original. Interview staples at Amazon, Google, Microsoft, Netflix — the classic Josephus problem being a famous recursion-based question.

Recursion is intentionally reached for on these — even knowing it costs more frames and call overhead — because the structure IS recursive. Interviewers test it precisely because it rewards understanding recursion deeply rather than avoiding it. 🎯

MISCONCEPTION PATROL · THE FOUR WRONG SENTENCES (T6)

"A recursive function must fully finish before anything prints."

Example 2's trace shows printing INTERLEAVED with the calls — each frame prints at the exact point where its println sits, not all at once at the end.

WRONG ✗

"I'll use break to exit the function."

Compile-time error — break is reserved for loops and switch. return is the ONLY valid early exit from a function (Example 4 exists purely to prove this).

WON'T COMPILE ✗

"Recursion is the more advanced choice, so it's always better."

Example 6's scorecard says otherwise: iteration wins on memory AND calls whenever both are viable. Recursion's value comes from specific problem shapes (Example 8), not general superiority.

WRONG ✗

"The base condition can go after the recursive call — same thing."

Check it after and the recursive call has ALREADY happened — the check is defeated. Base condition at the very start, before any recursive call. No exceptions.

WRONG ✗

PRACTICE · T6Five questions — draw the frame tower for each trace.

  1. Trace fun(4) from Example 2 step by step: list every stack frame created, what each one prints (if anything), and the final printed output.
  2. A learner removes the if (n < 1) return; line from Example 2 entirely. Describe exactly what will happen when this code runs.
  3. Rewrite Example 7 (sumDown) as an equivalent iterative for loop, and state how many stack frames each version uses for sumDown(4).
  4. True/False with justification: "For any problem that can be solved with a simple counting loop, recursion will use less memory than iteration."
  5. Name one category of problem (from Example 8) where recursion is generally preferred despite its overhead, and explain why in one sentence.

Frames on paper: grow up, pop down. Predict print-or-pop before each.

T6 SOLUTIONS
  • Q1Frames: fun(4) prints 4 → fun(3) prints 3 → fun(2) prints 2 → fun(1) prints 1 → fun(0) hits base, prints NOTHING, pops. Then 1, 2, 3, 4 pop in reverse. Peak depth 5 frames. Output: 4 3 2 1.
  • Q2Runaway recursion: prints 4 3 2 1 0 −1 −2 … with a NEW frame per call, until the stack segment runs out of space → the program terminates with a StackOverflowError (Example 1's exact failure mode).
  • Q3for (int i = 4; i >= 1; i--) { System.out.println("Adding: " + i); } — recursive version: 5 frames for sumDown(4) (n = 4,3,2,1,0); iterative version: 1 frame (the containing method's own).
  • Q4False. Recursion creates one frame per call, each with its own variable copy; iteration reuses one frame and one variable. For loop-solvable problems, iteration always uses less memory (Example 6: 16 bytes vs 4 bytes).
  • Q5Any of: tree traversal / merge sort / quick sort / binary search / DP with memoization (or the Josephus problem) — because the problem's structure is itself self-similar, so the recursive code directly mirrors the shape of the problem.

TOPIC 7 · PART 15 · STATIC — COMPLETING THE VARIABLE PICTURE (BONUS)

One copy. Owned by the class. Shared by every object.

Quick recap from T5: instance = directly inside a class → heap; local = directly inside a method → stack. Today the third and final category: a static variable or method belongs to the class itself, not to any one object. Every object shares the exact same single copy — zero per-object duplication. Static members live in the Static segment — the fourth room we named in T5 but left empty until now.

EXAMPLE 1 · THREE VARIABLES, THREE CATEGORIES, ONE CLASS

Demo.java · THE THREE-WAY SPLIT
1class Demo
2{
3 int a; // instance — directly inside the class
4 static int b; // static — inside the class, WITH the static keyword
5 void method()
6 {
7 int c; // local — directly inside a method
8 }
9}
Three variables, three memory rooms: a → heap (per object) · b → static segment (ONE copy for the whole class) · c → stack (per method call). Distinguished purely by location plus, for static, the keyword — never by name or type.

HEAP

a per object · defaults on new

STATIC

b ONE shared copy · whole class

STACK

c per call · no default

THE DECISION TEST — SHOULD THIS METHOD BE STATIC?

Does executing this method require data specific to ONE particular object?
YES NO
INSTANCE METHOD

Tied to a specific object reference — the answer depends on WHICH object you ask. Lives with the heap data it reads.

STATIC METHOD

Same answer no matter which object (or no object at all) — belongs to the class, called via the class name.

Run every "should it be static?" exam question through this ONE question. Not vibes — the test.

EXAMPLE 2 · MILEAGE VS HEART RATE — THE TEST, WORKED IN CODE

CarVsHuman.java · ONE OF EACH
1class Car
2{
3 double mileage; // instance — differs per car
4 double getMileage()
5 {
6 return mileage; // depends on THIS car → instance method
7 }
8}
9class Human
10{
11 static double averageHeartRate()
12 {
13 return 72.0; // same answer for everyone → static
14 }
15}
16// ...inside main:
17Car myCar = new Car();
18myCar.mileage = 18.5;
19System.out.println(myCar.getMileage());
20System.out.println(Human.averageHeartRate());
OUTPUT · SPOT THE CALLING DIFFERENCE
> 18.5
> 72.0
Line 19 REQUIRED an object (a Maruti and a BMW answer differently — the result depends on which car). Line 20 needed NO object at all — called straight through the class name. That's the whole decision test in two lines.
Calling convention: static → ClassName.member, no new, no reference. The exact opposite of T4's rule that instance members always need a specific object.

EXAMPLE 3 · THE SHARED COUNTER — THREE OBJECTS, ONE PURPLE BUBBLE

Counter.java · SHARED, NOT DUPLICATED
1class Counter
2{
3 static int totalObjects = 0; // ONE shared copy across every Counter
4 Counter()
5 {
6 totalObjects++; // every new object bumps the SAME shared copy
7 }
8}
9Counter c1 = new Counter();
10Counter c2 = new Counter();
11Counter c3 = new Counter();
12System.out.println(Counter.totalObjects);
OUTPUT · PREDICT: 3? OR THREE 1s?
> 3
3 — NOT three separate values of 1. Each new Counter() incremented the exact same static variable, proving there's only ever ONE copy — unlike an instance variable, which gets its own independent copy per object (T4).

THE MEMORY PICTURE — THREE HEAP OBJECTS, ONE STATIC BUBBLE, THREE ARROWS IN

HEAP · one bubble PER object

Counter #1 c1 → · tick! → +1
Counter #2 c2 → · tick! → +1
Counter #3 c3 → · tick! → +1

STATIC · one bubble for the CLASS

totalObjects = 1 after c1
totalObjects = 2 after c2 — SAME box, ticked up
totalObjects = 3 after c3 — never a second bubble
All three constructor arrows land on the ONE purple bubble — the static zone never gains a second copy no matter how many objects you create. Purple = shared-by-the-class, the same colour we used for the shared-object pulse in T4.

TOPIC 7 · PART 16 · STYLE TRAPS, NAME RULES & THE FINAL CLASSIFICATION

It compiles. It's still wrong style. And the name trick has a limit.

Three last pieces: a call that compiles but lies, the real limit on same-name variables, and the cold classification drill that closes the whole variable picture.

EXAMPLE 4 · THE CALLING-CONVENTION TRAP — LEGAL ≠ GOOD

CORRECT STYLE — VIA THE CLASS NAME

Human.averageHeartRate()says what it is: class-owned

COMPILES… BUT MISLEADING

Human h = new Human();
h.averageHeartRate()
also compiles — Java allows it
Java technically permits calling a static method through an object reference — but it's discouraged precisely because it IMPLIES the result depends on that specific object, which for a static method it never does. Write ClassName.member, always.

EXAMPLE 5 · ALL THREE CATEGORIES IN ONE CLASS — AND A REAL NAME CONSTRAINT

Reading.java · COEXISTENCE
1class Reading
2{
3 int value; // instance — per-object
4 static int value2; // static — shared (deliberately a DIFFERENT name…)
5 void update()
6 {
7 int value; // local — this call only
8 value = 10;
9 // touches neither the instance nor the static one —
10 // each is classified purely by where it's declared
11 }
12}
Why value2, not value? Unlike T5's instance/local same-name trick, a static and an instance variable in the SAME class genuinely cannot share an identical name in real Java — a real language constraint, not a style choice. The name trick has a hard limit, and this is it.
All three categories coexist happily in one class — told apart by declaration location plus the static keyword, never by any naming pattern.

EXAMPLE 6 · THE COLD CLASSIFICATION DRILL — ANSWER BEFORE REVEALING

class Store { String name; static int branchCount; void restock() { int itemsAdded; itemsAdded = 50; } }
?name — classify it, out loud, before pressing.
nameINSTANCE — inside the class, not inside a method, no static keyword. Heap, per object.
?branchCount — classify.
branchCountSTATIC — inside the class AND marked static. Static segment, one shared copy.
?itemsAdded — classify.
itemsAddedLOCAL — inside a method. Stack, no default (but assigned before read, so legal).
Three for three = the full variable picture is yours. All four JRE rooms — code, static, heap, stack — have now had their tenants introduced. T5 named the rooms; T7 filled the last one.

ONE MORE RULE WORTH KNOWING — STATIC CAN'T TOUCH INSTANCE

A static method cannot directly access an instance variable. A static method isn't tied to any particular object — and instance variables only exist once an object has been created. Which object's field would it even read? This bites the moment a class mixes both kinds of members (Examples 3 and 5) — and it's why main (a static method!) always had to create objects before touching their fields.

MISCONCEPTION PATROL · THE FOUR WRONG SENTENCES (T7)

"Each object gets its own copy of the static variable."

Example 3 disproves this by construction: three objects, ONE shared counter, printing 3 — never three separate 1s.

WRONG ✗

"It doesn't seem to need an object, so I'll make it static."

Vibes aren't the test. The real test: does the RESULT depend on object-specific data? Run the flowchart, not the feeling.

NOT THE TEST ✗

"A static method can freely read instance variables of its class."

It cannot — no specific object exists to draw instance data from. Instance variables only exist once an object has been created.

WRONG ✗

"The same-name trick from T5 works for static too."

A static and an instance variable in the same class CANNOT legally share an identical name — a real language constraint (Example 5's note), not a style preference.

WRONG ✗

PRACTICE · T7Four questions — flowchart first, then classify.

  1. Given class Bank { double balance; static double interestRate; void deposit(double amt) { double newTotal; newTotal = balance + amt; } } — classify all three variables, justifying each with the location/keyword rule.
  2. A learner writes a method isPrime(int n) that uses only the parameter n and no object data. Should it be static? Justify with the decision test.
  3. True/False with justification: "If a class creates 100 objects, a static variable declared in that class exists in 100 separate copies, one per object."
  4. Explain, in one or two sentences, why a static method cannot directly reference an instance variable of its own class.

Location + keyword. Then the one-question flowchart. That's the whole toolkit.

T7 SOLUTIONS
  • Q1balance — inside the class, no static → instance (heap, per object). interestRate — inside the class, static keyword → static (static segment, one shared copy). newTotal — inside deposit() → local (stack, no default, assigned before read).
  • Q2Yes — static. The result depends only on the parameter n, never on any particular object's data — the decision test routes it straight to the static branch.
  • Q3False. A static variable belongs to the CLASS — exactly one copy exists in the static segment no matter how many objects are created (Example 3: three objects, one counter, prints 3).
  • Q4A static method isn't tied to any specific object, and instance variables only exist inside created objects — so there is no object to read the field from. (Which of the 100 objects' balance would it mean?)

ADD-ON · PART 17 · CLOSE

Seven ideas the exam hides. You now own all seven.

One line each — if any line feels foggy, its part number is right there. Re-run it before Unit 2.

  • T1Two's complement (P3–5) — n bits hold −2ⁿ⁻¹ … 2ⁿ⁻¹−1; MSB=1 means DECODE (subtract 1, flip, convert, sign) — never read raw.
  • T2OR · AND · XOR (P6) — three tiny truth tables, applied column by column with zero interaction between columns.
  • T3Shifts & NOT (P7–8) — << doubles, >> halves keeping sign (amber filler), >>> forces blue 0s (positives agree, negatives diverge wildly); ~x = −(x+1).
  • T4Value vs reference (P9–10) — = photocopies a primitive's value but copies an object's ADDRESS: one object, many names, every name sees every change.
  • T5Memory model (P11–12) — four JRE rooms; instance → heap with free defaults, local → stack with NO defaults (compile error); classify by LOCATION, never name.
  • T6Recursion (P13–14) — every call stacks a frame; base condition BEFORE the call or StackOverflowError; return exits, break doesn't compile; iteration is cheaper when both work.
  • T7Static (P15–16) — one class-owned copy in the static segment; the test is "does the answer depend on WHICH object?"; call via ClassName.member; static can't touch instance.
YOUR FOLDER AFTER THIS ADD-ON — CHECK BEFORE YOU LEAVE
Desktop\java-practice\u1-addon\
BitwiseCheck.java <- T2 · verifies the OR/AND/XOR columns
BitwiseCheck.class <- javac made it · never edit it
CarShare.java <- T4 · one object, two names
CarShare.class
Dog.java <- T5 · defaults proof · run java Demo
Dog.class + Demo.class <- one javac, TWO .class files
Controlled.java <- T6 · the base condition that saves the stack
Controlled.class
Counter.java <- T7 · static vs instance census
Counter.class
LoopVersion.java <- T6 · same countdown, zero self-calls
LoopVersion.class
UNIT 1 ADD-ON · THE COMPACTED SEVEN 17 PAGES · ZERO ASSETS · ALL SIMS HAND-BUILT