Unit 2 home
CLASS 15 · PART G SINGLETON · ABSTRACT · NESTED UNIT II · UI24PC320CS
CLASS 15 · P 1/14PGDN NEXT POINT · PGUP BACK

Vasavi College of Engineering (Autonomous) · CSE · B.E. III Sem · R-24

A class that refuses
to be created twice.

Yesterday you learned that private hides a field. Today you will do something that sounds like a mistake: put private on a constructor — the one thing whose entire job is to be called from outside. It looks like sabotage. It is actually how the campus Wi-Fi stops you logging in twice.

CLASS15 of 60Part G · indigo · Unit 2
SYLLABUS ITEMS3 of 5Singleton · Abstract · Nested
PYQs LANDING2 questionsP2·Q12a · P1·Q4
YOU WILL WRITE4 programsin Eclipse, from scratch

THE OFFICIAL SYLLABUS SENTENCE THIS HOUR SERVES

“Classes and Interfaces: Singleton class, Abstract class, Nested class, Interface, Package.”

PART 2 · WHERE WE ARE · g218b

One class in the whole app — and how Java enforces it

Class 14 gave you a lock for data. This hour hands you the same lock and asks a stranger question: what if the thing that must be controlled is not a value, but the number of objects that exist?

BY THE END OF THIS HOUR YOU CAN

  • Design a class that can only ever produce one object, and explain the two pieces that make it work.
  • Classify any nested class you are shown into one of Java's four kinds.
  • Debug the classic Singleton mistake — a getInstance() that quietly hands out a second object.
  • Trace what an abstract method call actually does at runtime across several subclasses.

THE ROAD THROUGH THIS CLASS

P1 · Cover — the three topics in one syllabus sentence
P2 · Where we are — from “lock a value” to “lock the object count”
P3 · Abstract classes, deepened — from Class 11's definition to a real hierarchy that a subclass must complete
P4 · Abstract Reservation with ReserveTrain and ReserveBus PYQ P2·Q12a · 4M
P5 · Singleton — why the campus Wi-Fi cannot allow two live sessions for one roll number
P6 · The implementation: a private constructor plus a static getInstance() — then broken on purpose
P7 · Can a class with only a private constructor ever have an instance? PYQ P1·Q4 · 2M
P8 · The honest footnote — a debt we note, not pay: two threads can still break this Singleton
P9 · Nested classes — the map of all four kinds
P10 · Kind 1 of 4 — static nested class
P11 · Kind 2 of 4 — member inner class
P12 · Kind 3 of 4 — local inner class (self-study, full program on the page)
P13 · Kind 4 of 4 — anonymous inner class, the one real Java uses most
P14 · Two activities — design a Wi-Fi Singleton, then classify four nested snippets; both with locked solution sheets

CLASS 15 OF 60 · 14 PARTS (13 CORE-TAUGHT + 1 SELF-STUDY) · 4 PROGRAMS YOU TYPE YOURSELF · 2 PYQs · 2 ACTIVITIES WITH LOCKED SOLUTION SHEETS · FEEDS LAB 3

A HONEST WORD ABOUT TODAY'S THREE TOPICS

These three sit in one syllabus sentence, but they are not one idea. Abstract class is about incomplete classes that force subclasses to finish them. Singleton is about counting — exactly one object, forever. Nested class is about where a class is allowed to live.

What genuinely connects them is the theme you started in Class 13 and continued in Class 14: deliberately taking power away from the code that uses your class, so that it cannot make a mistake. Abstract removes the power to leave a method undefined. Singleton removes the power to say new. Nested classes remove the power to use a helper class from somewhere it does not belong. Keep that thread in mind and the hour holds together.

PART 3 · ABSTRACT CLASSES, DEEPENED · g219

A parent that refuses to answer

Class 11 told you what the word abstract means. It did not show you the bug that abstract was invented to kill. That bug is what we build first — in real code, in Eclipse — and then we let one keyword destroy it.

First, exactly what you already have

Nothing here is new. Read it as a checklist — if any row feels unfamiliar, that is the row to revise tonight, because the rest of this part stands on all four.

YOU LEARNED INTHE IDEATHE SYNTAXWHY TODAY NEEDS IT
Class 10Inheritance — a child class acquires a parent's fields and methodsclass Professor extends CollegeStaffAn abstract class is only useful as a parent. No inheritance, no point.
Class 11Overriding — a child rewrites a method it inheritedsame name, same parameters, in the childCompleting an abstract method is overriding. Same rules apply.
Class 11Runtime polymorphism — a parent-typed variable can hold a child object, and the child's method runsCollegeStaff s = new Professor();This is the whole payoff. Without it an abstract class is just a rule-book nobody reads.
Class 11abstract means “incomplete — cannot be instantiated”abstract class CollegeStaffToday that one-line definition grows into six enforceable rules.
The honest gap in Class 11. There, abstract arrived as a definition to memorise while we were busy with polymorphism. You could quote it in an exam but you had never been hurt by its absence, so it felt like a rule for the sake of a rule. The next three screens fix that: we will write a program that compiles perfectly, runs perfectly, and prints a completely wrong salary — and then watch abstract turn that silent wrong answer into a compiler error.

Step 1 · The problem — a parent forced to invent an answer

Here is a real situation from any college office. Staff salaries are calculated differently for different kinds of staff: a visiting professor is paid per lecture, a lab assistant is paid per hour, a librarian is on a fixed monthly amount. But every one of them has a name and a staff ID, and every one of them has a salary.

So you do the sensible thing you learned in Class 10 — put the common part in a parent class:

THINK

Before you look at the code, answer this in your head: the parent class CollegeStaff must declare calculateSalary(), because every staff member has a salary and we want to call that method through a parent-typed variable.

But what body do you write inside the parent's version? The parent genuinely does not know. It has no lecture count, no hourly rate, no fixed pay. Whatever you write there is a guess. Hold that discomfort — it is the entire reason abstract exists.

WHERE THIS FILE LIVES · ECLIPSE, EXACTLY AS ON THE LAB MACHINES

eclipse-workspace — JavaClass15/src/BrokenStaff.java — Eclipse IDE
FileEditSourceRefactorNavigateSearchProjectRunWindowHelp

PACKAGE EXPLORER

JavaClass15
src
BrokenStaff.java
JRE System Library
BrokenStaff.java
1class CollegeStaff
2{
3 // ... the code we are about to type
4}

HOW TO GET HERE · File › New › Java Project, name it JavaClass15, click Finish. Then right-click the src folder › New › Class, name it BrokenStaff, tick public static void main(String[] args), click Finish. Leave the package box empty — Eclipse will warn about the default package; that warning is fine until Class 16, where packages are the topic.

ECLIPSE SAVES IT AS eclipse-workspace\JavaClass15\src\BrokenStaff.java
BrokenStaff.java · PIECE 1 OF 3 — THE PARENT THAT GUESSES (lines 1–14)
1class CollegeStaff
2{
3 String name;
4
5 CollegeStaff(String staffName)
6 {
7 name = staffName;
8 }
9
10 double calculateSalary()
11 {
12 return 0; // the parent has to invent something
13 }
14}

LINE 12 IS THE MISTAKE — AND IT LOOKS HARMLESS

An ordinary parent class: a name, a constructor, and a salary method. But look at line 12 — return 0;.

The parent has no idea how any particular staff member is paid, so it invented an answer. That invented answer is the bug, and it will not show up for another thirty lines.

Piece 2 of 3 · two children. One of them does its job properly. The other quietly does not.

BrokenStaff.java · PIECE 2 OF 3 — ONE GOOD CHILD, ONE FORGETFUL (lines 16–42)
16class Professor extends CollegeStaff
17{
18 int lectures;
19
20 Professor(String staffName, int lectureCount)
21 {
22 super(staffName);
23 lectures = lectureCount;
24 }
25
26 double calculateSalary()
27 {
28 return lectures * 1200;
29 }
30}
31
32class LabAssistant extends CollegeStaff
33{
34 int hours;
35
36 LabAssistant(String staffName, int hoursWorked)
37 {
38 super(staffName);
39 hours = hoursWorked;
40 }
41 // we FORGOT calculateSalary() — and nothing complains
42}

LOOK AT LINE 41 AND NOTHING ELSE

Three classes, and only one line matters: line 41, the comment saying we forgot calculateSalary(). LabAssistant never wrote a salary rule.

Here is the problem. Nothing complains. No red underline, no compiler error. Because the parent on line 10 invented a rule (return 0;), the child is free to inherit it and stay silent.

Keep that in mind for the next piece, where we run it.

The exact mechanism of the lie. LabAssistant has no calculateSalary() of its own, so it silently inherits the parent's version — the one that returns the invented 0. Inheritance did precisely what Class 10 taught it to do. The fault is not in inheritance; it is that we gave the parent a body it had no right to have.

Now the part that does the damage — eight lines of perfectly ordinary main, which is exactly why the bug is so dangerous.

BrokenStaff.java · PIECE 3 OF 3 — main(), AND THE LIE (lines 44–53)
44public class BrokenStaff
45{
46 public static void main(String[] args)
47 {
48 CollegeStaff a = new Professor("Sridevi", 40);
49 CollegeStaff b = new LabAssistant("Ramesh", 90);
50 System.out.println(a.name + " salary = " + a.calculateSalary());
51 System.out.println(b.name + " salary = " + b.calculateSalary());
52 }
53}
ECLIPSE CONSOLE · REAL RUN
<terminated> BrokenStaff [Java Application]
Sridevi salary = 48000.0
Ramesh salary = 0.0
Press Ctrl + F11 in Eclipse to run. Look at the second line. Ramesh worked 90 hours and the program says he is owed zero rupees. There was no error, no warning, no red underline — the program ran to completion and produced a confident, wrong number.
Why 48000.0 and not 48000? calculateSalary() is declared to return double, so 40 * 1200 (an int) is widened to a double before it leaves the method — the automatic widening from Class 4. And return 0; becomes 0.0 for the same reason.

Step 2 · The keyword: abstract

Read these seven cards in order. This is the same shape we use for every new term in this course — plain words, an analogy, the syntax, a tiny example, what happens inside, the output, and then one more example to make it stick.

1 · PLAIN

In the simplest possible words: an abstract method is a method with a name but no body — a promise that the method exists, with no instructions for how to do it. An abstract class is a class that contains such a promise, and therefore cannot be used to make an object.

The parent stops pretending it knows the answer. Instead of returning a made-up 0, it says: “every staff member has a salary calculation, and I am not the one who defines it — my subclasses must.”

2 · ANALOGY

The blank college form. The office prints a leave-application form. Every form has the same fields: name, roll number, dates, reason. The form guarantees that a reason will be given — there is a labelled box for it — but the printed form does not contain a reason. It cannot. It does not know yours.

A blank form is not a leave application. You cannot submit the blank form itself; you fill in a copy of it and submit that. The printed form is the abstract class. The labelled empty box is the abstract method. Your filled copy is the subclass object. And notice the office designed it this way on purpose: by printing the box, they made it impossible to submit a form with no reason.

3 · SYNTAX

Two places the word appears, and one punctuation mark that surprises everybody:

abstract class CollegeStaff // 1. on the class
{
abstract double calculateSalary(); // 2. on the method — ends in a SEMICOLON
}

There are no curly braces after calculateSalary(). The line ends with ;. Adding a brace pair after it — even an empty one — is a compile error, because an empty body is still a body, and abstract means no body at all. This single semicolon is the most commonly mistyped character in this topic.

4 · SMALLEST EXAMPLE

The whole idea fits in six lines. Nothing else is needed to see it work:

abstract class Shape
{
abstract double area();
}
class Square extends Shape
{
double side = 4;
double area()
{
return side * side;
}
}

new Square() is legal — Square is complete. new Shape() is a compile error — Shape has a hole in it.

5 · WHAT HAPPENS INSIDE

Why can't Java just create an abstract object? Think about what new actually does, from Class 8: it reserves memory on the heap for the object's fields, runs the constructor, and hands back a reference. Then, when you later call a method on that reference, the JVM looks up the method's code address in the class's method table and jumps there.

For an abstract method there is no code address to jump to. The slot in the table is empty. So if Java allowed new CollegeStaff(), then staff.calculateSalary() would be a jump to nowhere — a crash with no possible recovery. Java therefore refuses at compile time, which is the earliest and cheapest moment to refuse. The rule is not arbitrary; it is the only safe option.

Notice what this means: abstract costs nothing at runtime. It is a promise checked entirely by the compiler. By the time your program is running, every object in memory is a fully-completed subclass object with every slot filled.

6 · THE OUTPUT

Here is the payoff. Add abstract to the parent class and its method, save (Ctrl + S), and Eclipse marks line 32 in red before you even run it — the class LabAssistant line, because that is the class carrying the unkept promise:

ECLIPSE PROBLEMS VIEW · THE ERROR YOU WANT
BrokenStaff.java:32: error: LabAssistant is not abstract and does not
override abstract method calculateSalary() in CollegeStaff
class LabAssistant extends CollegeStaff {
^
1 error
Read the message aloud — it is unusually helpful. It names the guilty class, names the method you forgot, and names the parent that demanded it. The silent wrong answer of 0.0 has become a red error you cannot ignore. That is the entire value of the keyword.
7 · ONE MORE, TO FIX IT IN PLACE

Payment methods in the college fee portal. Every payment has an amount and a receiptNo — genuinely shared, so they belong in the parent. Every payment must be collected somehow, but how differs completely: UPI opens an app, a card reads a PIN, cash gets counted at the counter.

So abstract class Payment holds amount, receiptNo and a normal, fully-written printReceipt() — and one line: abstract void collect();. Any new payment type the college adds next year cannot compile until it says how money is collected. That is a design decision enforced by the compiler instead of by a reminder email.

Step 3 · See it: the hole, the block, the fill

This diagram builds in four presses. In LEARNING mode press NEXT PIECE; in TEACHING mode each click of the clicker adds the next piece.

BUILD-UP · WHY new IS REFUSED ON AN ABSTRACT CLASS

abstract class CollegeStaff String name; ✓ complete calculateSalary() NO BODY — a hole new CollegeStaff() COMPILE ERROR the JVM would have nowhere to jump class Professor extends CollegeStaff calculateSalary() { return lectures*1200; } fills the hole new Professor() ALLOWED — every slot is filled HEAP name = "Sridevi" lectures = 40 a real object exists

AN ABSTRACT CLASS IS A DESIGN, NOT A THING · ONLY A COMPLETED SUBCLASS BECOMES AN OBJECT

THE SENTENCE THAT UNLOCKS THE WHOLE TOPIC

An abstract class exists to be inherited, never to be instantiated. Every confusing exam question about abstract classes becomes easy once you hold that. It is a half-built machine on the factory floor: genuinely useful, genuinely valuable, and impossible to drive off the lot.

And note the direction of the benefit. abstract does not help the person writing CollegeStaff — it helps the person who writes Librarian next year and would otherwise have shipped a silent 0.0. Abstract classes are a message to future programmers, enforced by the compiler.

Step 4 · The fixed program, complete — three kinds of staff, one loop

Now the real thing. Same story, corrected, with the third subclass added and all three paid from a single loop. Create a new class in the same Eclipse project so you keep the broken one for comparison.

eclipse-workspace — JavaClass15/src/StaffPayrollDemo.java — Eclipse IDE
FileEditSourceRefactorNavigateSearchProjectRunWindowHelp

PACKAGE EXPLORER

JavaClass15
src
BrokenStaff.java
StaffPayrollDemo.java
JRE System Library
BrokenStaff.java StaffPayrollDemo.java
1abstract class CollegeStaff
2{
3 // four classes in one file — type them from the panel below
4}

RIGHT-CLICK srcNew › Class › name it StaffPayrollDemo › tick public static void mainFinish. The other three classes are typed above and below it in the same file — legal because only StaffPayrollDemo is public, and the file is named after it. That rule is from Class 3 and still holds.

ECLIPSE SAVES IT AS eclipse-workspace\JavaClass15\src\StaffPayrollDemo.java

BEFORE YOU TYPE · THE WHOLE FILE IN FOUR SENTENCES

One file, four classes, and you will build it in six small pieces — none of them longer than about twenty lines. Here is the shape before any detail:

  1. Piece 1CollegeStaff's ordinary half: two fields, a constructor, two getters.
  2. Piece 2 — the same class's promise, plus one finished method that uses it.
  3. Piece 3Professor, the first class to keep the promise.
  4. Piece 4LabAssistant, keeping it a second way.
  5. Piece 5Librarian, keeping it a third way.
  6. Piece 6main(), where one line of code runs all three rules.

If you only remember one thing: everything after piece 2 is impossible until piece 2 exists, because the promise has to be made before anybody can keep it.

Piece 1 of 6 · the ordinary half. Not one new idea here — two fields, a constructor and two getters, exactly as in Class 14. Type it quickly.

StaffPayrollDemo.java · PIECE 1 OF 6 — THE ORDINARY HALF (lines 1–20)
1abstract class CollegeStaff
2{
3 private String name;
4 private String staffId;
5
6 CollegeStaff(String staffName, String idCode)
7 {
8 name = staffName;
9 staffId = idCode;
10 }
11
12 public String getName()
13 {
14 return name;
15 }
16
17 public String getStaffId()
18 {
19 return staffId;
20 }
Notice the class is already abstract on line 1 — but nothing so far explains why. Twenty lines in, this looks like any normal class. The reason arrives in the very next piece.
Nothing runs yet. There is no main here, and CollegeStaff can never be built with new. That is expected.

Piece 2 of 6 · the promise, and the method that trusts it. Eleven lines — and this is the piece that makes the class abstract.

StaffPayrollDemo.java · PIECE 2 OF 6 — THE PROMISE (lines 22–32)
22 // PROMISE: every staff member has a salary rule.
23 // I refuse to guess what it is. No body — just a semicolon.
24 public abstract double calculateSalary();
25
26 // a NORMAL method — abstract classes may be partly complete
27 public void printPayslip()
28 {
29 System.out.printf("%-10s %-7s Rs %10.2f%n",
30 name, staffId, calculateSalary());
31 }
32}
Stop and look at line 24. It ends in a semicolon and has no braces. That single character is the whole idea of this class: the parent is saying “every staff member has a salary rule, and I refuse to guess what it is.”
Why printf and not println? %-10s means “a string, left-aligned, padded to 10 characters”, and %10.2f means “a floating-point number, right-aligned in 10 characters, exactly 2 decimals”. That is what makes the columns line up. %n is the newline. This is the formatted output from Class 5, used here for a real reason.
Nothing runs yet. There is no main in this piece, and CollegeStaff can never be built with new. That is expected — a promise on its own does no work.

Piece 3 of 6 · the first class that keeps the promise. Fifteen lines, and only one of them is the interesting one.

StaffPayrollDemo.java · PIECE 3 OF 6 — Professor (lines 34–48)
34class Professor extends CollegeStaff
35{
36 private int lectures;
37
38 Professor(String staffName, String idCode, int lectureCount)
39 {
40 super(staffName, idCode);
41 lectures = lectureCount;
42 }
43
44 public double calculateSalary() // keeps the promise
45 {
46 return lectures * 1200.0;
47 }
48}
Line 44 is the promise being kept. Same name, same return type, same (empty) parameter list as the parent's declaration on line 24 — that is what makes it an override rather than a new method. Now it has a body, so Professor is a complete class and new Professor(...) is legal.
Why super(staffName, idCode) on line 40 is genuinely required. The parent's two fields are private, so this class cannot touch them directly. Handing the values up to the parent's constructor is the only way to set them — this is one of the few places super is not optional.

Piece 4 of 6 · the same move again. Read this quickly — it is deliberately almost identical to piece 3.

StaffPayrollDemo.java · PIECE 4 OF 6 — LabAssistant (lines 50–64)
50class LabAssistant extends CollegeStaff
51{
52 private int hours;
53
54 LabAssistant(String staffName, String idCode, int hoursWorked)
55 {
56 super(staffName, idCode);
57 hours = hoursWorked;
58 }
59
60 public double calculateSalary()
61 {
62 return hours * 180.0;
63 }
64}
Compare this with piece 3, line by line. The structure is identical — a field, a constructor that calls super, and calculateSalary(). Only the rule differs: hours × 180 instead of lectures × 1200.

Piece 5 of 6 · the third and last rule. Fifteen lines. This one is the simplest of all — a fixed monthly pay.

StaffPayrollDemo.java · PIECE 5 OF 6 — Librarian (lines 66–80)
66class Librarian extends CollegeStaff
67{
68 private double monthlyPay;
69
70 Librarian(String staffName, String idCode, double pay)
71 {
72 super(staffName, idCode);
73 monthlyPay = pay;
74 }
75
76 public double calculateSalary()
77 {
78 return monthlyPay;
79 }
80}
Three salary rules, three shapes. lectures × 1200, hours × 180, and a flat monthlyPay returned as-is. They have nothing in common except the name of the method — and that is exactly what makes the next piece work.
Notice what is missing. Neither class writes printPayslip(). They inherit the finished one from line 27 and only supply the missing piece. That division of labour is the reason to choose an abstract class over an interface here.

Piece 6 of 6 · the payoff. Eighteen lines, and the whole lesson lands on just one of them.

StaffPayrollDemo.java · PIECE 6 OF 6 — main() (lines 82–99)
82public class StaffPayrollDemo
83{
84 public static void main(String[] args)
85 {
86 CollegeStaff[] payroll =
87 {
88 new Professor("Sridevi", "VCE101", 40),
89 new LabAssistant("Ramesh", "VCE102", 90),
90 new Librarian("Anitha", "VCE103", 32000)
91 };
92
93 System.out.println("---- VCE PAYROLL ----");
94 for (CollegeStaff s : payroll)
95 {
96 s.printPayslip(); // same call, three different rules
97 }
98 }
99}
ECLIPSE CONSOLE · REAL RUN
<terminated> StaffPayrollDemo [Java Application]
---- VCE PAYROLL ----
Sridevi VCE101 Rs 48000.00
Ramesh VCE102 Rs 16200.00
Anitha VCE103 Rs 32000.00
Read the order in which those lines arrived. The header printed at press 55, from line 93 — before the loop even existed. Then line 96 revealed and all three payslips arrived together, because that single line runs three times. Ramesh is finally paid: 90 × 180 = 16200. Three rows, three completely different salary rules, one line of calling code. Nobody had to remember to add an if for the new Librarian type; the loop simply worked.
Line 86 is the sentence that proves the design. CollegeStaff[] payroll — an array of a type that can never be instantiated. Perfectly legal, because the array holds references, and every reference points at a complete subclass object. This is the abstract class doing its real job: being a common type.

LINE BY LINE — THE SIX LINES THAT CARRY THE LESSON

Line 1 — abstract class CollegeStaff The word abstract in front of class does exactly one thing: it makes new CollegeStaff(...) illegal. Everything else about the class behaves normally — it still has fields, a constructor, and working methods.

Lines 6–10 — a constructor in an abstract class. This surprises almost every student: an abstract class can have a constructor even though you can never call new on it. It is not dead code. When line 88 runs new Professor(...), the Professor constructor's super(name, id) on line 40 calls this very constructor to initialise the inherited part of the object. The abstract constructor runs on every single subclass object ever created.

Line 24 — public abstract double calculateSalary(); The promise. No braces, ends in a semicolon. From this line onward, any class that extends CollegeStaff and is not itself abstract must provide this method or refuse to compile.

Lines 27–31 — printPayslip(), a fully written method. Proof that an abstract class is not required to be entirely empty. This is the difference from an interface as you knew it in Class 11: the abstract class can carry shared, finished behaviour. Even better, look at line 30 — the finished method calls the unfinished one. When printPayslip() runs on Ramesh's object, that call lands in LabAssistant's version. The parent is calling code that did not exist when the parent was written. This pattern has a name in industry — the template method — and it is why abstract classes are so useful.

Lines 86–91 — CollegeStaff[] payroll = { ... } One array, mixed subclass objects, declared with the abstract parent as its type. Runtime polymorphism from Class 11 is what makes this safe.

Line 96 — s.printPayslip(); The payoff line. At compile time Java only knows s is some CollegeStaff. At runtime the JVM looks at the actual object in the heap and jumps to that class's calculateSalary(). Three different bodies run from one line of source, and adding a fourth kind of staff next year requires zero changes here.

Step 5 · The six rules — and what an examiner does with them

These are the rules exam questions are built from. Every one of them you have now seen in the program above, so read the middle column and point at the line that proves it.

THE RULEWHY IT IS TRUEPROVED BY
An abstract class cannot be instantiatedAn abstract method has no code address, so a call on such an object would jump nowhere. Java refuses at compile time.new CollegeStaff(...) → error
An abstract class can have a constructorIt runs via super(...) when a subclass object is created, to initialise the inherited fields.lines 6–10 with line 40
An abstract class can have normal, complete methods and fieldsOnly the methods you mark abstract are unfinished. This is the main advantage over an interface.printPayslip(), lines 27–31
A class with even one abstract method must be declared abstractOtherwise the compiler could not stop you instantiating an incomplete class.line 1 needs abstract because of line 24
A subclass must override every abstract method — or be declared abstract itselfThe promise has to be kept somewhere down the chain before an object can exist.the LabAssistant error earlier
An abstract method cannot be private, static or finalEach of those makes overriding impossible, and an abstract method that cannot be overridden could never be completed — a contradiction.see the warning below

THE THREE FORBIDDEN COMBINATIONS — A FAVOURITE 2-MARK QUESTION

abstract finalfinal means “cannot be extended / overridden”, abstract means “must be extended / overridden”. A direct contradiction. Real javac message: illegal combination of modifiers: abstract and final.

abstract private — a private method is invisible to the subclass, so the subclass cannot override it. The promise could never be kept. Message: illegal combination of modifiers: abstract and private.

abstract static — a static method belongs to the class, not to an object, so it is resolved at compile time and is not overridden at all. Message: illegal combination of modifiers: abstract and static.

All three share one explanation, and it is the sentence to write in an exam: “an abstract method exists only to be overridden, so any modifier that prevents overriding cannot be combined with it.”

Step 6 · Legal or not? Say it out loud before you look

Six lines. For each one decide compiles or error, and say why in one sentence. The answer badge on the right is what you check against — not what you read first.

CollegeStaff s = new Professor("A", "V1", 10);

Abstract type on the left, complete subclass on the right.

COMPILES

CollegeStaff s = new CollegeStaff("A", "V1");

Trying to create the abstract class itself.

ERROR — CollegeStaff is abstract; cannot be instantiated

abstract class Fee { double amount; }

An abstract class with no abstract method at all.

COMPILES — legal, though usually pointless

class Fee { abstract void collect(); }

An abstract method inside a class that is not abstract.

ERROR — Fee is not abstract and does not override…

abstract void collect()

Marked abstract, then given an empty pair of braces as its body instead of a semicolon.

ERROR — abstract methods cannot have a body

abstract class Casual extends CollegeStaff

A subclass with an empty body that does not override calculateSalary() — but is itself abstract.

COMPILES — the promise is passed further down

Rows 1 and 6 are the two that separate the students who understand abstract from the ones who memorised “cannot create object”.

Where this goes next. You now have abstract classes as working machinery, not vocabulary — which means the exam question that has been waiting since Class 11 is finally answerable. Part 4 is that question: Paper 2, Q12(a), four marks, an abstract Reservation class with two subclasses. We will answer it completely, in the examiner's own words.
PART 4 · PREVIOUS YEAR QUESTION · g220

The reservation question, answered in full

This is a write-a-program question, not a definition question — and it is worth four marks in ten minutes of writing. We will do it the way you should do it in the hall: understand, plan, sketch, then write clean code you can defend.

THE QUESTION, EXACTLY AS PRINTED
QUESTIONWrite a Java program to create an abstract class named Reservation that contains an abstract method reserve(). Create two subclasses ReserveTrain and ReserveBus that implement the reserve() method to display appropriate messages.
PAPERPaper 2 · Q12(a) · 4 marks · Unit II
WHAT IT ASKSFour separate deliverables, and each one is being marked: (1) an abstract class Reservation, (2) an abstract method named exactly reserve() inside it, (3) two subclasses named exactly ReserveTrain and ReserveBus that each override reserve(), (4) a main method that actually creates the objects and calls the method, so a message is displayed. Miss the main and the program “displays” nothing.
CONCEPTS NEEDEDabstract class and method (Part 3, today) · extends (Class 10) · overriding (Class 11) · runtime polymorphism (Class 11) · System.out.println (Class 3) · one public class per file (Class 3)
MARK BUDGETRoughly 1 mark for the abstract class + abstract method written correctly, 1 mark for each correct subclass, and 1 mark for a working main with output. Write all four pieces even if you are rushed — a half-finished program with all four pieces present scores better than a beautiful program missing main.

THE WORD “IMPLEMENT” IN THIS QUESTION IS A TRAP

The question says the subclasses “implement the reserve() method”. In everyday English that just means “write the body of”. But implements is also a Java keyword, and it is used for interfaces, never for classes.

Every year some students write class ReserveTrain implements Reservation. That does not compile, because Reservation is an abstract class, not an interface. The correct keyword here is extends. Read the question as “subclasses that provide a body for reserve()” and you will not slip.

The diagram to draw before you write a single line

Thirty seconds with a pen. It is the standard UML class-hierarchy sketch you learned in Class 10, with one new convention: abstract names are written in italics. Draw it in your answer sheet — examiners give credit for a correct hierarchy diagram, and more importantly it stops you from forgetting a subclass.

Reservation «abstract» + reserve() no body — a promise extends ReserveTrain + reserve() prints the train message ✓ promise kept ReserveBus + reserve() prints the bus message ✓ promise kept UML convention: an abstract class and its abstract methods are written in italics. The hollow triangle always points at the parent.

PAPER 2 · Q12(a) · DRAW THIS FIRST — IT IS THE ANSWER'S SKELETON

Step-by-step: the plan, before any code

Five steps, in this order. This ordering is not decorative — if you write the subclasses before the parent you will keep having to scroll back and change things.

STEP 1

Write the parent first: abstract class Reservation. Inside it put exactly one line, abstract void reserve(); — and check the semicolon. Return type void is correct here because the question says “display a message”, which means printing, not returning a value.

STEP 2

Write class ReserveTrain extends Reservation. Inside, override reserve() with a real body: a System.out.println with a train-specific message. Spell the names exactly as the question printed themReserveTrain, capital R, capital T, no space, no underscore. Examiners do notice.

STEP 3

Copy that shape for ReserveBus. Same structure, different message. Do not get creative here — the marks are for the structure being right twice, not for a clever second implementation.

STEP 4

Write the public class with main. Create one object of each subclass and call reserve() on each. Declare the variables using the parent typeReservation r1 = new ReserveTrain(); — because that demonstrates runtime polymorphism and it is the version an examiner is hoping to see.

STEP 5

Below the program, write the expected output in two lines, and add one sentence of explanation: “the reference is of the abstract parent type but the overridden subclass method executes at runtime — runtime polymorphism.” That single sentence is often what lifts an answer from 3 to 4.

The program — real, compilable, exam-length

Type this in Eclipse now, in the same JavaClass15 project. It is deliberately short: this is the amount of code a 4-mark answer should be. Every line earns something.

eclipse-workspace — JavaClass15/src/ReservationDemo.java — Eclipse IDE
FileEditSourceRefactorNavigateSearchProjectRunWindowHelp

PACKAGE EXPLORER

JavaClass15
src
BrokenStaff.java
StaffPayrollDemo.java
ReservationDemo.java
JRE System Library
StaffPayrollDemo.java ReservationDemo.java
1abstract class Reservation
2{
3 abstract void reserve();
4}

RIGHT-CLICK srcNew › Class › name it ReservationDemo › tick public static void mainFinish. Type the other three classes into the same file. Save with Ctrl + S — Eclipse compiles as you save, so a red mark in the left margin means fix it now, before running.

ECLIPSE SAVES IT AS eclipse-workspace\JavaClass15\src\ReservationDemo.java
ReservationDemo.java · PIECE 1 OF 2 — PARENT + TWO CHILDREN (lines 1–22)
1// PYQ Paper 2 · Q12(a) · 4 marks
2abstract class Reservation
3{
4 // the PROMISE: no body, ends in a semicolon
5 abstract void reserve();
6}
7
8class ReserveTrain extends Reservation
9{
10 void reserve() // promise kept
11 {
12 System.out.println("Train seat reserved: Kacheguda - Tirupati, coach S4, berth 32.");
13 }
14}
15
16class ReserveBus extends Reservation
17{
18 void reserve() // promise kept, differently
19 {
20 System.out.println("Bus seat reserved: Hyderabad - Vijayawada, seat 14, window.");
21 }
22}

WRITE THIS MUCH FIRST, IN THE EXAM

Six lines make the promise (1–6). Seven lines keep it one way (8–14). Seven more keep it another way (16–22). That is already most of the marks.

Three things the examiner checks on line 5: the word abstract is there, there are no braces, and it ends in a semicolon.

And on lines 8 and 16: extends, never implementsReservation is a class, not an interface.

Piece 2 of 2 · main(). Thirteen lines that earn the rest of the marks.

ReservationDemo.java · PIECE 2 OF 2 — main() (lines 24–35)
24public class ReservationDemo
25{
26 public static void main(String[] args)
27 {
28 // parent-typed reference, child object — runtime polymorphism
29 Reservation r1 = new ReserveTrain();
30 Reservation r2 = new ReserveBus();
31
32 r1.reserve(); // runs ReserveTrain's body
33 r2.reserve(); // runs ReserveBus's body
34 }
35}
ECLIPSE CONSOLE · REAL RUN · Ctrl + F11
<terminated> ReservationDemo [Java Application]
Train seat reserved: Kacheguda - Tirupati, coach S4, berth 32.
Bus seat reserved: Hyderabad - Vijayawada, seat 14, window.
Watch the two lines arrive one press apart — and that timing is the answer. The train line appeared when line 32 revealed; the bus line only when line 33 revealed. Same method name reserve(), called through the same parent type Reservation, yet each call landed in a different body. That is runtime polymorphism watched happening, not merely asserted. This is your expected output — copy it into the answer sheet under a heading that says Output:. An examiner scanning for it will find it immediately.
Why no public before void reserve()? Both are fine. Left as default (package-private) it is shorter to write under exam pressure, and legal because all four classes are in the same file and therefore the same package. If you do write public abstract void reserve(); in the parent, you must write public void reserve() in both children — an override may widen access but never narrow it. Mismatching that is a real compile error, so pick one style and be consistent.
Why only ReservationDemo is public. Java allows at most one public class per .java file, and the file must be named after it. The other three classes have no modifier, so they legally share the file. In the exam this is exactly right — four small classes, one file, one page.

LINE BY LINE — EVERY LINE, IN ORDER

Line 2 — abstract class Reservation Declares the parent and marks it incomplete. From here, new Reservation() is a compile error anywhere in the program. This line is the first thing an examiner looks for.

Line 5 — abstract void reserve(); The promise itself, and the single most error-prone line in the answer. Three things to check every time: the word abstract is present, there are no braces, and it ends with a semicolon. void because the method prints rather than returns.

Line 8 — class ReserveTrain extends Reservation extends, not implements. Because Reservation has an unfulfilled abstract method, this class now must provide reserve() or the compiler will reject it by name.

Lines 10–13 — the override. Same name, same parameter list (empty), same return type (void) as the parent's declaration — that is what makes it an override rather than a new, unrelated method. Now it has a real body, so the promise is kept and ReserveTrain is a complete class that can be instantiated.

Lines 16–22 — the second subclass. Structurally identical, semantically different. This is the point of the question: one promise, two independent ways of keeping it.

Line 29 — Reservation r1 = new ReserveTrain(); The most interesting line in the program. Left of = is an abstract type; right of = is a concrete object. Both halves are legal, and together they are legal, because the abstract type is used only as a label for the reference, never to build an object. The object on the heap is a full ReserveTrain.

Lines 32–33 — the calls. The compiler checks “does type Reservation have a method called reserve()?” — yes, it is declared on line 5, so the call is allowed. Then at runtime the JVM asks the object which body to run, and gets two different answers. Compile-time checking against the parent, runtime execution from the child: that is runtime polymorphism in one sentence.

The output, and precisely why it comes out that way

WHAT HAPPENS AT LINE 32 · THE LOOKUP THE JVM PERFORMS

STACK · main() r1 declared type: Reservation the COMPILER only sees this. It checks: does Reservation declare reserve()? Yes → OK. HEAP ReserveTrain object actual class: ReserveTrain reserve() → has a real body points at AT RUNTIME · r1.reserve() the JVM ignores the declared type and asks the OBJECT which body → ReserveTrain.reserve() runs Train seat reserved: Kacheguda ...

COMPILE TIME CHECKS THE PARENT · RUNTIME RUNS THE CHILD · THAT IS THE WHOLE MECHANISM

WHY THE OUTPUT IS WHAT IT IS — THREE REASONS, IN ORDER

1. Why any output at all? Because main creates real objects and calls the method. This sounds obvious, but a program with the perfect class hierarchy and no main prints nothing and loses the display mark. The question asked for messages to be displayed.

2. Why the train message and not the parent's? The parent has no message — it has no body at all. There is literally nothing else that could run. Java resolves the call using the object's actual class, which is ReserveTrain.

3. Why in that order? Java executes statements top to bottom, and println writes immediately. Line 25 before line 26, so train before bus. Swap the two lines and the output order swaps — there is no hidden cleverness here.

THE MODEL ANSWER · AS IT SHOULD LOOK ON YOUR SHEET

PAPER 2 · Q12(a) 4 MARKS UNIT II MODEL ANSWER
4/4

Q12(a)  Write a Java program to create an abstract class Reservation with an abstract method reserve(); create subclasses ReserveTrain and ReserveBus.  [4M]

An abstract class is a class declared with the abstract keyword. It cannot be instantiated and may contain abstract methods — methods declared without a body, which every concrete subclass must override.

Program:

abstract class Reservation
{
abstract void reserve();
}
class ReserveTrain extends Reservation
{
void reserve()
{
System.out.println("Train seat reserved: Kacheguda - Tirupati, coach S4, berth 32.");
}
}
class ReserveBus extends Reservation
{
void reserve()
{
System.out.println("Bus seat reserved: Hyderabad - Vijayawada, seat 14, window.");
}
}
public class ReservationDemo
{
public static void main(String[] args)
{
Reservation r1 = new ReserveTrain();
Reservation r2 = new ReserveBus();
r1.reserve();
r2.reserve();
}
}

Output:
Train seat reserved: Kacheguda - Tirupati, coach S4, berth 32.
Bus seat reserved: Hyderabad - Vijayawada, seat 14, window.

Explanation: Reservation cannot be instantiated because reserve() has no body. Each subclass supplies its own body. The references r1 and r2 are of the abstract parent type, but the overridden subclass method executes at runtime — this is runtime polymorphism.

IF THE QUESTION SAYS “ALSO ADD A CONSTRUCTOR” OR “ADD A CONCRETE METHOD”

Variants of this question appear with small additions. Both are easy if you remember Part 3: an abstract class may have a constructor (called through super(...) from the subclass) and may have ordinary methods with bodies. So you could add String passenger; plus a Reservation(String passenger) constructor, and a concrete void showPassenger() — and the answer only gets stronger. What you can never do is new Reservation(...).

What goes wrong in this answer — and the takeaway

Writing implements instead of extends

Caused by the word “implement” in the question text. implements is only for interfaces. With an abstract class you must write extends, and the wrong keyword does not compile at all.

Giving the abstract method a body — opening a brace pair after abstract void reserve()

Even an empty pair of braces counts as a body. Real error: abstract methods cannot have a body. The declaration must end in a semicolon and nothing else.

Forgetting abstract on the class

Students write abstract void reserve(); inside a plain class Reservation. Real error: Reservation is not abstract and does not override abstract method reserve(). Both places need the keyword.

No main method — or no calls inside it

The classes are perfect and the program displays nothing. The question says “display appropriate messages”, so the display is being marked. Always create both objects and call both methods.

Trying new Reservation() in main

Usually written out of habit, to “test the parent”. Real error: Reservation is abstract; cannot be instantiated. There is nothing to test — the parent is a design.

Renaming the classes

TrainReservation instead of ReserveTrain, or bookSeat() instead of reserve(). The question printed exact names; changing them costs marks for no benefit at all.

Narrowing access in the override

Parent says public abstract void reserve();, child says void reserve(). Real error: attempting to assign weaker access privileges. Keep the modifiers matching.

Writing no output section

Code alone, no Output: heading. Cheap marks left on the table — two lines of text you already know.

KEY TAKEAWAY

Four pieces, always in this order: abstract parent → abstract method with a semicolon → two subclasses using extends and overriding it → a main that creates both objects through parent-typed references and calls the method. Then write the two output lines and the one polymorphism sentence.

And the idea underneath, which is worth more than the marks: the parent declares what must happen; each child decides how. Every abstract-class question in every paper is that one sentence wearing a different domain — reservations this year, shapes or payments or vehicles the next. Recognise the shape and the question is already half answered.

Where this goes next. Abstract classes remove the power to leave a method undefined. Part 5 turns to the second syllabus item — the Singleton class — which removes something far stranger: the power to write new at all. We start, as always, with the problem: two Wi-Fi sessions for one roll number.
PART 5 · THE SINGLETON IDEA · g221

When a second object is a bug

Everything you have been taught for twelve classes says: need an object? Write new. This part is about the small number of situations where a second new is not a feature but a security hole — and where the right fix is to make new illegal.

Step 1 · The problem — one roll number, two live Wi-Fi sessions

You know the college Wi-Fi login page. You enter your roll number and password, and you get a session. The college has bought bandwidth for a fixed number of concurrent sessions, so the rule is simple and strict: one roll number, one live session. If you log in on your phone and then log in on a laptop, the first session must be closed — not duplicated.

Now imagine the software that tracks the current session on your device. A first attempt, using everything you know so far, looks completely reasonable:

THE OBVIOUS DESIGN — AND ITS HOLE
class WifiSession
{
String rollNo;
long dataUsed;
}
// somewhere in the login screen:
WifiSession s1 = new WifiSession();
// somewhere in the settings screen:
WifiSession s2 = new WifiSession();
Two objects. Two dataUsed counters. Neither knows about the other. The student has one connection but the software believes in two, so usage is counted in two places and the 2 GB daily cap is never reached.
WHAT WE ACTUALLY WANT
// login screen:
WifiSession s1 = WifiSession.getInstance();
// settings screen:
WifiSession s2 = WifiSession.getInstance();
// s1 and s2 are the SAME object
// s1 == s2 → true
One object, reached from two places. Every screen that asks for the session gets the same one, so dataUsed is a single truthful number. Note that nobody wrote new.
THINK

Before reading on, consider the obvious “solutions” and why each fails:

“Just be careful — only call new once.” This is a rule in somebody's head, not in the program. Six months later a new developer adds a screen, writes new WifiSession() because that is what Java taught them, and the compiler cheerfully agrees. Nothing in the code stopped them.

“Pass the one object around to everything that needs it.” Better — and for many designs this is genuinely the right answer. But it means every screen, every helper, every logger must accept the session as a parameter, and any one of them can still write new.

The real requirement is stronger than both: we need it to be impossible to obtain a second object — enforced by the compiler, the way private made s.marks = 5000 impossible yesterday.

Step 2 · The name: Singleton class

This is the first of the five syllabus items and the only one that is entirely new to you. Same seven-card treatment as always.

1 · PLAIN

In the simplest possible words: a Singleton class is a class written so that only one object of it can ever exist, and that one object is handed out to anyone who asks.

The name says it: single + -ton — a single one. Two pieces make it work, and you already know both of them separately: a private constructor (Class 13's private, applied somewhere new) and a static method that returns the one object (Class 9's static).

2 · ANALOGY

The college Principal. Vasavi has exactly one Principal. Not one per department, not one per building — one, for the whole institution. Any office that needs a decision does not create a Principal; it asks “who is the Principal?” and is directed to the same person.

Now notice the mechanism, because it is exactly Java's: there is no procedure by which a department can appoint its own Principal. The ability to create one is not merely discouraged — it does not exist. That is the private constructor. And there is a published way to reach the existing one: the office directory. That is getInstance().

A weaker analogy you will see in books is “the President of a country”. Use whichever you find easier, but keep the two-part structure: no way to create, one published way to reach.

3 · SYNTAX

The complete shape, three ingredients, in this order. This is the skeleton to memorise:

class WifiSession
{
private static WifiSession instance; // 1. the ONE object, held by the class
private WifiSession() // 2. PRIVATE constructor — blocks `new`
{
}
public static WifiSession getInstance() // 3. the only public door
{
if (instance == null)
{
instance = new WifiSession(); // legal HERE — inside the class
}
return instance;
}
}

Read the three comments again in order. Nothing here is a new keyword — private, static, if, null, new, return are all things you have used for weeks. The Singleton is not new syntax. It is a new arrangement of old syntax. That is what a design pattern means.

4 · THE ONE SURPRISING LINE

A private constructor — private WifiSession() with an empty Allman body under it. Students stare at this line, and they are right to. A constructor's whole purpose is to be called from outside by new. Making it private appears to make the class useless.

Here is the resolution, and it is worth reading twice. From Class 13: private means “accessible only from inside this class”. It does not mean “dead”. So:

  • Outside the class — in main, in another class, anywhere — new WifiSession() is a compile error. The door is shut.
  • Inside the class — in getInstance(), which is a member of WifiSession itself — new WifiSession() is perfectly legal. The class can always build itself.

So the constructor is not disabled. It is reserved. The class takes sole control over its own creation — and that is the entire trick of the pattern.

5 · WHAT HAPPENS INSIDE, THE FIRST TIME

Trace getInstance() on the very first call, using the memory model from Class 8 and the static rules from Class 9:

Call 1. instance is a static field, so it lives with the class, not with any object, and it was initialised to Java's default for a reference: null. The if (instance == null) test is therefore true. So new WifiSession() runs, an object is created on the heap, and its address is stored in instance. That address is returned.

Call 2, from a completely different part of the program. instance is the same static field — there is only one of it in the whole program — and it now holds an address, not null. The if is false. The new is skipped entirely. The same address is returned.

Calls 3 to 3000. Identical to call 2. The object is created at most once, ever — and, worth noting, it is created only if somebody actually asks. This is called lazy initialisation: no session object is built while nobody has logged in.

6 · THE OUTPUT THAT PROVES IT

The proof is one comparison. From Class 6 you know that == on two references asks “are these the same object?” — not “do they look alike?”. So:

THE ONE LINE THAT SETTLES IT
s1 == s2 ? true
true means there is one object with two names. If a Singleton is written correctly this prints true; if it is broken it prints false. You will run exactly this test in Part 6, and you will use it to catch a deliberately sabotaged version.
7 · WHERE ELSE THIS APPEARS

Four more places where a second object would be a genuine bug — read them as a set, because the exam may use any domain:

A printer spooler. One queue for the department printer. Two queues means two programs each believing the printer is free, and pages interleave into nonsense.

A settings / configuration object. Read the config file once. Two objects means one screen using the old settings and another using the new ones.

A database connection pool. The pool exists to limit connections. Two pools means twice the limit — the pool has defeated itself.

A log file writer. Two writers with the same file open produces interleaved, corrupted lines.

The common thread: the object represents a single real-world resource. There is one printer, one config file, one Wi-Fi session, one Principal. Duplicating the object tells a lie about the world.

Step 3 · See it: the shut door and the one published route

Four presses. Watch the two attempts to reach the object: one through new, one through getInstance().

BUILD-UP · HOW A PRIVATE CONSTRUCTOR REDIRECTS EVERYONE THROUGH ONE DOOR

class WifiSession private static WifiSession instance one field, held by the CLASS — not by any object (static, Class 9) private WifiSession() the constructor — door SHUT to outsiders main() tries: new WifiSession() COMPILE ERROR public static getInstance() if (instance == null) create it — then return it THE ONLY PUBLISHED ROUTE login screen settings screen returns the SAME stored object every time Two screens asked. One object exists. s1 == s2 is true.

SHUT THE ONLY DOOR, THEN PUBLISH ONE WINDOW · THAT IS THE WHOLE PATTERN

WHY getInstance() HAS TO BE static

This is the question that catches people, and the answer is a lovely piece of logic. A non-static method can only be called on an object: something.method(). But if you have not got an object yet — and you cannot make one, because the constructor is private — then you could never call it. The method would be unreachable, and the class permanently unusable.

A static method is called on the class: WifiSession.getInstance(). No object needed. That is exactly the escape route the pattern requires, and it is why the static keyword from Class 9 is not optional decoration here — remove it and the design collapses.

Same reasoning for the field. instance must be static because it has to exist before the first object does, and because there must be exactly one of it for the whole program — which is precisely what “belongs to the class, not to an object” means.

LEARN THIS SENTENCE · IT IS THE DEFINITION AN EXAMINER ACCEPTS

“A Singleton class is a class that allows only one object (instance) to be created. It is implemented by making the constructor private so that no other class can instantiate it, keeping a private static reference to that single object, and providing a public static method — usually named getInstance() — that creates the object on first call and returns the same object on every later call.”

Then add one use: “used where exactly one object should represent a single shared resource — a configuration holder, a logger, a printer spooler, a database connection pool.” Definition + the three ingredients + one use = full marks on any Singleton question in this syllabus.

Where this goes next. You have the idea and the skeleton. Part 6 types the whole thing into Eclipse as a working program, runs the s1 == s2 test, then deliberately breaks it in the two ways students break it in exams — so you can recognise a broken Singleton on sight.
PART 6 · THE IMPLEMENTATION · g222

Building it — then breaking it on purpose

A pattern you have only read is a pattern you will misremember. So: type it, run it, watch true appear — and then watch two small edits turn that true into false. The broken versions are the ones that show up in exam papers.

Step 1 · The complete, working Singleton

Same Eclipse project, a new class. This program does three things: proves only one object exists, proves the state is genuinely shared, and proves the compiler blocks new.

eclipse-workspace — JavaClass15/src/WifiSessionDemo.java — Eclipse IDE
FileEditSourceRefactorNavigateSearchProjectRunWindowHelp

PACKAGE EXPLORER

JavaClass15
src
BrokenStaff.java
StaffPayrollDemo.java
ReservationDemo.java
WifiSessionDemo.java
JRE System Library
ReservationDemo.java WifiSessionDemo.java
1class WifiSession
2{
3 private static WifiSession instance;
4 // ... type the rest from the panel below
5}

RIGHT-CLICK srcNew › Class › name it WifiSessionDemo › tick public static void mainFinish. Both classes go in this one file. Tip: if Eclipse shows a yellow warning lamp on the WifiSession class name, hover it — it is only the “default package” note, harmless until Class 16.

ECLIPSE SAVES IT AS eclipse-workspace\JavaClass15\src\WifiSessionDemo.java
WifiSessionDemo.java · PIECE 1 OF 3 — THE THREE INGREDIENTS (lines 1–25)
1class WifiSession
2{
3 // INGREDIENT 1 — the single object, held by the CLASS itself
4 private static WifiSession instance;
5
6 // ordinary per-object state — there will be only one object,
7 // so these are effectively the whole app's session data
8 private String rollNo = "(not logged in)";
9 private int dataUsedMB = 0;
10
11 // INGREDIENT 2 — PRIVATE constructor: nobody outside can say `new`
12 private WifiSession()
13 {
14 System.out.println("[WifiSession object created — happens once]");
15 }
16
17 // INGREDIENT 3 — the ONLY public way in. static, so no object needed.
18 public static WifiSession getInstance()
19 {
20 if (instance == null) // true ONLY on the first call
21 {
22 instance = new WifiSession(); // legal: we are inside the class
23 }
24 return instance; // same object, every time
25 }

THAT IS THE ENTIRE PATTERN · 25 LINES

Three ingredients, and you have now seen all three:

1. line 4 — a private static field to hold the one object.
2. line 12 — a private constructor, so nobody outside can say new.
3. line 18 — a public static door that hands out that one object.

Everything after line 25 is ordinary code of the kind you wrote in Class 14. Read the next two pieces quickly; the thinking is over.

Why the created-message is inside the constructor. A constructor runs exactly once per object, so printing from inside it is the most honest possible object-counter. In real code you would not leave a println there — but for learning, and for a viva, it is the clearest possible evidence.

Piece 2 of 3 · ordinary behaviour. Nothing here is about Singleton at all — it is the encapsulation you already know. It exists so the object has something real to remember.

WifiSessionDemo.java · PIECE 2 OF 3 — NORMAL METHODS (lines 27–43)
27 // normal encapsulated behaviour (Class 14)
28 public void login(String newRollNo)
29 {
30 rollNo = newRollNo;
31 dataUsedMB = 0;
32 }
33
34 public void use(int mb)
35 {
36 if (mb > 0) dataUsedMB += mb;
37 }
38
39 public void status()
40 {
41 System.out.println("roll=" + rollNo + " data=" + dataUsedMB + " MB");
42 }
43}
Three plain methods. login sets the roll number and resets the counter, use adds data (refusing negatives, the Class-14 guard), and status prints. No static, no instance — these run on the object, like every method you wrote before today.
Only one object will ever hold this state. That is what makes dataUsedMB effectively the whole application's data counter, even though it is written as ordinary per-object state.

Piece 3 of 3 · the proof. Two different “screens” each ask for the session, and we test whether they got the same object.

WifiSessionDemo.java · PIECE 3 OF 3 — main(), THE PROOF (lines 45–65)
45public class WifiSessionDemo
46{
47 public static void main(String[] args)
48 {
49
50 System.out.println("-- login screen asks for the session --");
51 WifiSession s1 = WifiSession.getInstance();
52 s1.login("1602-24-733-101");
53 s1.use(120);
54
55 System.out.println("-- settings screen asks for the session --");
56 WifiSession s2 = WifiSession.getInstance();
57 s2.use(80);
58
59 System.out.print("s1 == s2 ? ");
60 System.out.println(s1 == s2);
61
62 System.out.print("via s1: "); s1.status();
63 System.out.print("via s2: "); s2.status();
64 }
65}
ECLIPSE CONSOLE · REAL RUN
<terminated> WifiSessionDemo [Java Application]
-- login screen asks for the session --
[WifiSession object created — happens once]
-- settings screen asks for the session --
s1 == s2 ? true
via s1: roll=1602-24-733-101 data=200 MB
via s2: roll=1602-24-733-101 data=200 MB
Watch what did not happen at press 37. Line 56 called getInstance() a second time — and the console stayed still. No new [object created] line appeared, because instance was no longer null, so the new on line 22 was skipped entirely. That silence is the Singleton working. Then (2) s1 == s2 prints true — one object, two names. And (3) 120 + 80 = 200, visible through both references, because only one dataUsedMB exists anywhere in the program. The state is genuinely shared.
Why the created-message is inside the constructor. A constructor runs exactly once per object, so printing from inside it is the most honest possible object-counter. In real code you would not leave a println there — but for learning, and for a viva, it is the clearest possible evidence.
Note what the rollNo never had to do. The settings screen never received the roll number as a parameter, yet s2.status() knows it. That is the practical benefit: shared state without passing anything around. It is also the pattern's danger, which we will be honest about at the end of this part.

Step 2 · Do this now — try to cheat, and watch the compiler win

Ten seconds, and it converts a rule you were told into a fact you have seen. In main, add one line:

ADD THIS LINE, THEN PRESS Ctrl + S

Type WifiSession bad = new WifiSession(); inside main. Eclipse marks it red as you save, before you ever run the program:

ECLIPSE PROBLEMS VIEW · THE ERROR THAT PROVES THE DESIGN
The constructor WifiSession() is not visible
— and from the command line, javac words it as:
WifiSessionDemo.java:57: error: WifiSession() has private access in WifiSession
WifiSession bad = new WifiSession();
^
1 error
Compare this with yesterday's marks has private access in Student. It is the same mechanism. Yesterday private guarded a field; today it guards the constructor. The keyword did not change — only what we pointed it at. Now delete the line before moving on.

THE ONE-SENTENCE CONNECTION TO YESTERDAY

Class 14: put private on the data, and no outsider can corrupt the value. Class 15: put private on the constructor, and no outsider can corrupt the object count. Same tool, one level up. If you can say that sentence, you understand both classes.

Step 3 · Break it — the two ways students break a Singleton

Both of these appear in exam papers as “find the error in this program”. Look at each broken version, decide what the output becomes, then read the verdict.

SABOTAGE 1 · THE MISSING if
public static WifiSession getInstance()
{
instance = new WifiSession();
return instance;
}
Output becomes s1 == s2 ? false, and [object created] prints twice. Every call builds a fresh object and overwrites the stored one. The constructor is still private, so it looks like a Singleton and compiles perfectly — but it is not one. This is the most dangerous version, because nothing errors. The if (instance == null) is not a style choice; it is the pattern.
SABOTAGE 2 · THE FORGOTTEN static
private WifiSession instance;
// static removed from the FIELD
public static WifiSession getInstance()
{
if (instance == null) ...
Does not compile at all. Real error: non-static variable instance cannot be referenced from a static context. That is the Class 9 rule doing its job — a static method has no object, so it cannot see per-object fields. If static is removed from getInstance() instead, you get non-static method getInstance() cannot be referenced from a static context at the call site. Both keywords are load-bearing.

Constructor left as public WifiSession() with an empty body, everything else correct

Does getInstance() still work? Is it still a Singleton?

COMPILES — but NOT a Singleton: outsiders can still write new

Field kept private static but getInstance() made public static WifiSession getInstance() returning new WifiSession() directly

Never touches instance at all.

COMPILES — new object per call, s1 == s2 is false

Field made public static WifiSession instance;

Constructor still private, getInstance() still correct.

COMPILES — but any outsider can now do WifiSession.instance = null; and force a second object

All three ingredients present and correct

private static field, private constructor, public static getInstance with the null check.

A CORRECT SINGLETON — s1 == s2 is true

Notice that three of the four broken versions compile. A Singleton is not verified by the compiler — it is verified by s1 == s2.

INGREDIENTWHAT IT PREVENTSREMOVE IT AND…
private constructorOutsiders creating objects with newcompiles, but anyone can make unlimited objects — not a Singleton
private static fieldThe object being lost between calls, and outsiders resetting iteither a compile error (if static goes) or a resettable Singleton (if private goes)
public static methodThe class becoming unreachableno way to obtain the object at all — the class is dead
if (instance == null)A second object being built on the second callcompiles and runs, silently returns a new object every time — the invisible bug

Step 4 · An honest warning — and one real limitation

THE SINGLETON IS THE MOST OVER-USED PATTERN IN PROGRAMMING

You have just learned a tool that feels powerful, so here is the caution that comes with it. Because a Singleton is reachable from everywhere by name, it behaves very much like a global variable — and global mutable state is the thing that makes large programs hard to reason about. Any line in any file might have changed dataUsedMB, and you cannot tell by looking at a method's parameters.

The test to apply before using it: is there genuinely one of this thing in the real world? One printer, one config file, one live Wi-Fi session — yes. One Student, one BankAccount, one Reservation — obviously not, and making those Singletons would be a serious design error. Professional practice today is to prefer passing the shared object in as a parameter (“dependency injection”) and to reserve Singletons for genuinely single resources.

For your exam: know the pattern, write it correctly, and be able to say both its use and this caveat. An answer that mentions the global-state concern reads as understanding rather than memorising.

THE LIMITATION WE ARE NOT SOLVING TODAY — AND WHY THAT IS HONEST

The version you just wrote is correct for a program where one thing happens at a time, which is every program you have written so far. If two parts of a program ever ran simultaneously, both could reach line 17 — if (instance == null) — find null, and both proceed to create an object. Two objects. The Singleton broken by timing rather than by code.

Fixing that needs the keyword synchronized, and synchronized needs threads, which are Class 21 to Class 24. Teaching it here would mean teaching you to type a keyword you cannot yet explain — and this course does not do that.

So here is the honest position, and it is exam-safe. If a question asks for a Singleton, write the version above; it is the standard textbook answer and earns full marks. If a question specifically asks about thread safety, the answer is: “the simple lazy Singleton is not thread-safe; the standard remedies are to declare getInstance() as synchronized, or to initialise the instance eagerly at field declaration.” We return to this in Class 23 with the machinery to actually understand it.

THE OTHER SPELLING YOU MAY SEE IN BOOKS: EAGER INITIALISATION

Some textbooks write the field as private static WifiSession instance = new WifiSession(); and then getInstance() is just return instance; — no if at all. This is called eager initialisation: the object is built when the class is first loaded, whether anybody needs it or not. It is shorter, and it happens to be thread-safe for free. The version with the if is called lazy, and it is the one exam papers usually show because it demonstrates the null check. Both are correct Singletons. Know that the two exist and that the difference is when the object is created.

Where this goes next. You can now build and defend a Singleton. Part 7 is a two-mark exam question that goes straight at the strangest line in it: can a class whose constructor is private ever have an instance at all? Most students answer that wrongly on instinct.
PART 7 · PREVIOUS YEAR QUESTION · g222b

“Can it have an instance?” — two marks, one trap

A two-mark question you can answer in four lines — if you resist the instinctive answer. Most students read “private constructor”, think “nobody can create it”, and write “No”. That loses both marks.

THE QUESTION, EXACTLY AS PRINTED
QUESTIONCan a class with a private constructor have an instance? Justify your answer.
PAPERPaper 1 · Q4 · 2 marks · Unit II
WHAT IT ASKSA yes/no answer plus a justification. The words “justify your answer” mean the reasoning carries the marks, not the verdict. Roughly ½ mark for saying Yes, and 1½ marks for explaining who creates it and where — ideally naming the Singleton pattern.
CONCEPTS NEEDEDMeaning of private — accessible within the same class (Class 13) · constructors (Class 8) · static members (Class 9) · the Singleton pattern (Parts 5–6, today)
THE TRAPprivate does not mean “disabled” or “unusable”. It means “usable only from inside this class”. The whole question lives in that distinction. If your first instinct was “No”, you were reading private as off instead of as internal.

The diagram that makes the answer obvious

One boundary line, two arrows. The boundary is the class. private controls which arrows may cross it — and one of the two arrows starts inside.

class Config everything inside this border is “the same class” private Config() static Config getInstance() { return new Config(); } ALLOWED — same class class Main new Config() a DIFFERENT class private = “only from inside this border” — NOT “never” so an instance CAN exist; only outsiders are stopped from making one

PAPER 1 · Q4 · ONE BORDER, TWO ARROWS — THE ANSWER IS WHICH ONE CROSSES

Step-by-step: how to build a 2-mark answer

STEP 1

Answer the question in the first word: “Yes.” A two-mark answer has no room for a build-up. Examiners read fast; give them the verdict immediately.

STEP 2

State the meaning of private precisely: accessible only within the same class. This one clause is the justification — everything else follows from it.

STEP 3

Say who creates the object: a static method of the same class, because a static method needs no existing object to be called. Name it — getInstance().

STEP 4

Name the pattern — Singleton — and add a three-line code fragment. On a 2-mark question a tiny fragment is worth more than another sentence of prose, because it proves you can actually write it.

The proof program — short enough to run in a viva

This is the minimum program that settles the question. Type it, run it, and you own the answer.

ECLIPSE SAVES IT AS eclipse-workspace\JavaClass15\src\PrivateCtorProof.java
PrivateCtorProof.java · PIECE 1 OF 2 — THE SEALED CLASS (lines 1–24)
1class Config
2{
3 private static Config instance;
4 private String collegeName = "Vasavi College of Engineering";
5
6 private Config() // PRIVATE constructor
7 {
8 System.out.println("Config object built INSIDE the class.");
9 }
10
11 public static Config getInstance()
12 {
13 if (instance == null)
14 {
15 instance = new Config(); // LEGAL — same class
16 }
17 return instance;
18 }
19
20 public String getCollegeName()
21 {
22 return collegeName;
23 }
24}

THE SAME THREE INGREDIENTS, ON A NEW DOMAIN

Line 3 the private static slot, line 6 the private constructor, line 11 the public static door. If that shape feels familiar now, the pattern has landed.

Line 15 is the one students query: new Config() inside Config. Perfectly legal — private means “only from inside this class”, and we are inside it.

Piece 2 of 2 · the proof. Eleven lines, one of them deliberately commented out.

PrivateCtorProof.java · PIECE 2 OF 2 — main() (lines 26–36)
26public class PrivateCtorProof
27{
28 public static void main(String[] args)
29 {
30 // Config c = new Config(); // ← would NOT compile
31
32 Config c = Config.getInstance(); // this works
33 System.out.println("Instance exists? " + (c != null));
34 System.out.println("College: " + c.getCollegeName());
35 }
36}
ECLIPSE CONSOLE · REAL RUN
<terminated> PrivateCtorProof [Java Application]
Config object built INSIDE the class.
Instance exists? true
College: Vasavi College of Engineering
Instance exists? true. That single line is the answer to a 2-mark exam question, demonstrated rather than argued. And notice when each line arrived: the constructor's message appeared from line 32 — a line that never mentions new. The object was born inside getInstance(), out of sight, which is precisely the point of the pattern. Line 30 stays commented out; uncomment it and the program stops compiling, which is the other half of the proof.
Why the output is what it is. Line 23 calls a static method on the class, which needs no object — so it is reachable even though no object exists yet. Inside it, line 11 runs new Config(). That line sits within Config, so private permits it. The constructor's message prints, the object's address is stored, and the reference comes back non-null. Hence true.

THE MODEL ANSWER · TWO MARKS, FOUR LINES AND A FRAGMENT

PAPER 1 · Q4 2 MARKS UNIT II MODEL ANSWER
2/2

Q4  Can a class with a private constructor have an instance? Justify your answer.  [2M]

Yes — such a class can have an instance.

A private member is accessible only within the same class. It is not disabled. Therefore code written inside the class can still call the constructor; only code in other classes is prevented from using new.

The object is normally created by a public static method of the same class — static, because it must be callable without an existing object. This is exactly the Singleton design pattern, used when only one instance should exist.

class Config
{
private static Config instance;
private Config() // private constructor
{
}
public static Config getInstance()
{
if (instance == null)
{
instance = new Config(); // legal: same class
}
return instance;
}
}
// use: Config c = Config.getInstance();

Hence a private constructor does not prevent instances — it only restricts who may create them, moving that control into the class itself.

IF THE EXAMINER ASKS A FOLLOW-UP

“Give another use of a private constructor.” A utility class — a class of only static helper methods, where an object would be meaningless. Java's own java.lang.Math is written this way: its constructor is private, which is why new Math() is illegal while Math.sqrt(25) works perfectly. You have been using a class with a private constructor since Class 4 without knowing it.

“Can a private constructor be inherited / can such a class be extended?” No — a subclass constructor must call super(...), and a private constructor is invisible to the subclass. So a class whose only constructor is private cannot be extended. That is often exactly what the designer wanted.

What goes wrong in this answer — and the takeaway

Answering “No”

The instinctive answer, and it loses both marks at once. It comes from reading private as “switched off” rather than “internal only”.

Saying “Yes” with no justification

The question printed the words justify your answer. A bare “Yes” is worth about half a mark. The reasoning is the question.

Forgetting static in the explanation

“A method inside the class creates it” is incomplete — a non-static method would itself need an object first. Saying static is what shows you followed the logic through.

Never naming the Singleton pattern

One word, and it signals you know this is standard practice rather than a curiosity. Cheap marks.

KEY TAKEAWAY

Yes — because private means “inside this class only”, not “nowhere”. The class keeps the power to create itself and takes that power away from everybody else. A public static getInstance() is how it then shares the result.

Carry the bigger sentence too, because it is the spine of both Class 14 and Class 15: access modifiers do not switch features off — they decide who is allowed to use them.

Where this goes next. Two of the five syllabus items are now done. Before we move to nested classes, Part 8 takes two minutes to close the thread-safety question honestly, so that you have a correct sentence ready if an examiner asks — and know exactly which later class earns you the full explanation.
PART 8 · A DEBT WE ARE NOTING, NOT PAYING · g223

The two-minute honest footnote

There is no code in this part, on purpose. A real gap exists in the Singleton you just wrote, and you deserve to know about it — but the fix requires vocabulary you will not have until Class 21. So we name the gap, give you the exam sentence, and book the appointment.

THE GAP, IN PLAIN ENGLISH

Every program you have written runs one instruction at a time, in order. Line 17 finishes before line 18 starts. Under that assumption your Singleton is airtight.

Real applications are often not like that. A phone app, a web server or a college portal can be doing several things at the same time — the login screen loading while a background task checks for updates. Java calls each of these independent streams of execution a thread, and that is the whole of Unit II's third topic.

Here is the problem in one picture, no code needed. Two threads reach getInstance() at almost the same moment, when instance is still null:

  • Thread A tests instance == nulltrue. It starts creating the object.
  • Before A finishes storing it, thread B tests instance == null → also true, because A has not written the field yet.
  • Both create objects. Two objects exist. The Singleton is broken — not by a typo, but by timing.

Notice what kind of bug this is: it depends on the exact instant each thread arrives, so it may appear once in ten thousand runs and never in testing. That is why it matters, and also why it needs proper machinery rather than a memorised keyword.

WHAT TO WRITE IF AN EXAMINER ASKS — LEARN THESE THREE LINES

Q: “Is the Singleton pattern thread-safe? How can it be made thread-safe?”

A: “The simple lazy Singleton is not thread-safe: if two threads call getInstance() simultaneously while instance is still null, both may pass the null check and create separate objects. It can be made thread-safe by (1) declaring the method public static synchronized WifiSession getInstance(), so only one thread executes it at a time; or (2) using eager initialisationprivate static final WifiSession instance = new WifiSession(); — which the JVM performs safely once during class loading.”

That is a complete, correct, full-marks answer. Write it if asked, and do not volunteer it if you are not asked — on a 2-mark Singleton question, the basic version is what is being marked.

WHY WE ARE NOT WRITING THE CODE TODAY

We could have you type the word synchronized into line 16 right now. It would compile, and the Singleton would be safe. And you would not be able to explain a single thing about it — not what a lock is, not what “one thread at a time” costs, not why the alternative is sometimes better.

This course does not trade understanding for the appearance of progress. Class 21 introduces threads properly. Class 23 covers race conditions and synchronized, and we will return to this exact program and fix it with full understanding. Until then you have a correct sentence and an honest label on the gap — which is a much better position than a keyword you cannot defend in a viva.

Where this goes next. Syllabus items one and two are complete. Part 9 opens the third — nested classes — which is entirely new material and has four distinct kinds. We start by mapping all four so you never confuse them, then take them one at a time.
PART 9 · NESTED CLASSES · THE MAP · g224

A class living inside another class

Third syllabus item, and entirely new. Until now every class you have written sat at the top level of a file, side by side with the others. Java also lets a class be declared inside another class — and there are four different kinds of that, which is exactly why students find this topic confusing. So we map all four first.

Step 1 · Why would anyone want this? The problem first

Consider a linked list — or, closer to home, the college's online result system. A MarksSheet object needs to hold a list of individual subject entries. Each entry has a subject code, a grade and credits. So you need a small class for an entry.

Written the way you know, you would put MarkEntry beside MarksSheet as a separate top-level class. And it works. But three things are now true, and all three are mildly wrong:

The relationship is invisible

MarkEntry exists only to serve MarksSheet, but nothing in the code says so. A new developer sees two unrelated classes and has to guess.

It pollutes the namespace

MarkEntry is visible to the entire package. Anybody can use it for anything, including in ways that make no sense without a marks sheet.

It cannot be made truly private

A top-level class can never be private — Java forbids it. So you cannot say “this helper is nobody else's business”.

A nested class fixes all three at once. Put MarkEntry inside MarksSheet and the relationship is stated by the code itself, the name lives in the outer class's scope rather than the whole package, and — the part that is only possible when nested — you may declare it private, so it genuinely cannot be used from anywhere else.

THE ANALOGY — AND IT IS THE SAME THEME AS THE WHOLE HOUR

A room inside a department. The Computer Science department has a server room. It is not a building on campus with its own address — it exists within the department, it is reached through the department, and access to it is the department's business. Putting it on the campus map as a separate building would be both misleading and a security problem.

Same theme as abstract classes and Singletons: we are deliberately removing power from the outside world. Abstract removed the power to leave a method undefined. Singleton removed the power to call new. Nested classes remove the power to use a helper class from where it does not belong.

Step 2 · The four kinds — the map to keep in your head

Java's terminology here is genuinely awkward, so read this next sentence twice: “nested class” is the umbrella term for all four; “inner class” means specifically a nested class that is not static. Many students use the two words interchangeably and then cannot answer a question that depends on the difference.

NESTED CLASSES the umbrella term — all four 1. STATIC NESTED static class Inner needs NO outer object INNER CLASSES non-static — need an outer object three sub-kinds → 2. MEMBER INNER declared like a field, directly in the class 3. LOCAL INNER declared inside a METHOD self-study · Part 12 4. ANON- YMOUS no name at all

FOUR KINDS · ONE SPLIT THAT MATTERS: static OR NOT

KIND 1

Static nested class — declared inside the outer class with the static keyword. It is nested for organisation only: it does not need an outer object to exist, and it cannot see the outer object's instance fields. Think of it as a normal class that happens to live in another class's namespace.

Created as Outer.Inner obj = new Outer.Inner(); — the outer class's name is used like a folder path. Part 10 builds one.

KIND 2

Member inner class (usually just called an inner class) — declared inside the outer class without static. Each inner object is permanently attached to one outer object and can read and write that outer object's private fields directly. That access is the reason this kind exists.

Created as Outer.Inner obj = outerObj.new Inner(); — note the strange-looking outerObj.new, which exists precisely because an outer object is required. Part 11 builds one.

KIND 3

Local inner class — declared inside a method, like a local variable. It exists only within that method's braces; outside them the name does not exist at all. Used for a helper needed by exactly one method and nowhere else.

Marked SELF-STUDY in this course — Part 12 gives you the full explanation and a complete worked example to read on your own, because it is the rarest of the four in practice.

KIND 4

Anonymous inner class — a class with no name, declared and instantiated in a single expression. You write the class body inline, right where the object is needed, and it is used exactly once.

The most common of the four in real Java code — you will see it constantly with interfaces, and it is how Runnable is written in Class 21. Part 13 builds one.

THE VOCABULARY QUESTION THAT CATCHES PEOPLE

“Is a static nested class an inner class?” — No. By Java's own terminology, an inner class is a nested class that is not static. So the four kinds are: one static nested class, plus three flavours of inner class.

If an exam asks “what are the types of nested classes in Java?”, the safest complete answer is: “static nested classes and inner classes; inner classes are further of three types — member inner, local inner and anonymous inner.” That answer is correct under every textbook's wording, which is exactly why it is the one to memorise.

 STATIC NESTEDMEMBER INNERLOCAL INNERANONYMOUS
Declared where?in the class, with staticin the class, no staticinside a methodinside an expression
Has a name?yesyesyesNO
Needs an outer object?NOyesyes*yes*
Can it use outer instance fields?NOyesyesyes
How you create itnew Outer.Inner()outerObj.new Inner()new Inner() in the methodnew Type() followed by a class body in braces
Taught inPart 10Part 11Part 12 (self-study)Part 13

*unless the enclosing method is itself static, in which case there is no outer object to attach to.

Read the fourth row again — it is the whole topic in one line. The only functional difference that ever matters is whether the nested class can reach into the outer object's instance data. static says no; everything else says yes. If you remember only one row of that table, remember that one, because nearly every exam question on nested classes is testing it in disguise.
PART 10 · KIND 1 OF 4 · g225

Static nested — a class kept
inside a folder, not inside an object

We start with the easiest of the four kinds, because it behaves almost exactly like the classes you already write. The only new thing is where its name lives.

Why would anyone nest a class at all?

Here is the honest motivation, and it has nothing to do with cleverness. Suppose you are writing an ExamResult class, and each result needs to carry a small bundle of marks — internal, external, total. You could create a separate top-level class called Marks. But then Marks sits in your project as a public name that anything can use, even though it only makes sense next to an ExamResult.

A nested class fixes exactly that. You put Marks inside ExamResult, and now its full name is ExamResult.Marks — which reads like a folder path and tells every future reader “this helper belongs to that class”. That is the entire purpose of the static nested kind: organisation and naming, nothing more.

THE ONE RULE THAT DEFINES THIS KIND

A static nested class does not need an outer object to exist, and it cannot see the outer object's instance fields. Both halves of that sentence come from the same source — the meaning of static you learned in Class 9.

Recall that lesson: static means “belongs to the class, not to any object”. A static method could not touch instance fields because it had no object to read them from. A static nested class obeys the identical logic: it belongs to the outer class, so there is no outer object attached, so there are no instance fields to reach. You are not learning a new rule here — you are applying an old one to a class instead of a method.

THE SYNTAX, BUILT UP IN THREE PRESSES

STEP 1 · DECLARE IT

Write a normal class, but put it inside another class's braces and mark it static:

class ExamResult
{
static class Marks // nested + static
{
int internal, external;
}
}
STEP 2 · CREATE ONE

Use the outer class's name like a folder path. No ExamResult object is created anywhere — look carefully, there is only one new:

ExamResult.Marks m = new ExamResult.Marks();

This is the line that proves the rule. If the nested class needed an outer object, this line would be impossible.

STEP 3 · THE LINE THAT WILL NOT COMPILE

If ExamResult has an instance field — say String studentName — then code inside Marks cannot touch it:

error: non-static variable studentName cannot be referenced from a static context

Read that message closely: it is the same error text you met in Class 9 when a static main tried to use an instance field. Same rule, new place.

NOW THE REAL PROGRAM — TYPE IT IN ECLIPSE, ONE LINE PER PRESS

ECLIPSE · PACKAGE EXPLORER PATH JavaClass15 / src / (default package) / ExamResultDemo.java
ExamResultDemo.java · PIECE 1 OF 2 — A CLASS INSIDE A CLASS (lines 1–20)
1class ExamResult
2{
3 String studentName = "Sneha"; // INSTANCE field of the outer class
4
5 static class Marks // KIND 1 — static nested
6 {
7 int internal;
8 int external;
9
10 int total()
11 {
12 return internal + external;
13 }
14 // ✗ the four lines below would NOT compile here:
15 // int bad()
16 // {
17 // return studentName.length();
18 // }
19 }
20}

ONE KEYWORD IS DOING EVERYTHING HERE

Marks is declared static inside ExamResult. That single word means Marks does not need an ExamResult object to exist — it only borrows the outer class as a name.

The price is on lines 14–18, commented out: a static nested class cannot touch the outer object's ordinary fields, because there is no outer object to touch.

Lines 14–18 are commented out on purpose. Uncomment them in Eclipse and the red underline appears instantly, with the Class-9 error text: non-static variable studentName cannot be referenced from a static context. Doing this yourself for five seconds is worth more than reading the rule twice — try it, then comment it back.

Piece 2 of 2 · using it. Twelve lines — and line 26 is the one to memorise.

ExamResultDemo.java · PIECE 2 OF 2 — NO OUTER OBJECT NEEDED (lines 22–33)
22public class ExamResultDemo
23{
24 public static void main(String[] args)
25 {
26 ExamResult.Marks m = new ExamResult.Marks();
27 m.internal = 18;
28 m.external = 57;
29 System.out.println("Internal : " + m.internal);
30 System.out.println("External : " + m.external);
31 System.out.println("Total : " + m.total());
32 }
33}
ECLIPSE CONSOLE · REAL RUN · Ctrl + F11
<terminated> ExamResultDemo [Java Application]
Internal : 18
External : 57
Total : 75
Now look back at line 26 and count the objects this program created. Exactly one — a Marks. There is no ExamResult object anywhere in this run, yet studentName on line 3 sits there untouched and unreachable. That is the static nested class proven: it used the outer class purely as a name, never as an object.

YOU HAVE ALREADY USED ONE OF THESE

Java's own library is full of static nested classes. The clearest example: Map.Entry — the type that represents one key–value pair inside a map. It is nested inside Map because a “map entry” is meaningless without a map, and it is static because it holds only its own key and value. You will meet it properly in Class 27 when maps arrive. When you do, remember you already know what its dotted name means.

PART 11 · KIND 2 OF 4 · g226

Member inner — a class that lives inside an object

Delete one keyword from Part 10's program and the behaviour changes completely. That single deletion is the whole of this part — so we will do it deliberately and watch what it costs and what it buys.

Remove static. What actually changes?

Two things change, and they are opposite in sign — one is a cost, one is a benefit. Getting these two straight is the whole topic:

 WITH static (Part 10)WITHOUT static (this part)
Needs an outer object first?NOnew Outer.Inner()YESouterObj.new Inner()
Can read outer instance fields?NO — compile errorYES — even private ones
So it is useful when…the helper is self-containedthe helper must work on the outer object's data

Row 2 is the reason this kind exists. An inner class can reach the outer object's private fields directly, with no getter. That sounds like it breaks Class 13's encapsulation rule — and it is worth being precise about why it does not. private means “accessible only within this class”, and an inner class is literally written within that class. It is inside the wall, not a hole in it.

THE ANALOGY THAT MAKES outerObj.new Inner() STOP LOOKING STRANGE

Think of a college with a Department object, and inside it a HOD (Head of Department) inner class. A HOD is not a free-floating person in the abstract — a HOD is always the HOD of some particular department. “Head of Department” with no department attached is meaningless.

So Java refuses to let you create one out of thin air. You must first have a department, and then ask that department to produce its HOD: cse.new HOD(). Read the syntax aloud as “CSE, make me your HOD” and it stops being weird punctuation and becomes a sentence.

THE PROGRAM — SAME SHAPE AS PART 10, ONE KEYWORD LIGHTER

ECLIPSE · PACKAGE EXPLORER PATH JavaClass15 / src / (default package) / DepartmentDemo.java
DepartmentDemo.java · PIECE 1 OF 3 — THE OUTER CLASS (lines 1–10)
1class Department
2{
3 private String deptName; // PRIVATE — sealed from outside
4 private int studentCount;
5
6 Department(String branch, int strength)
7 {
8 deptName = branch;
9 studentCount = strength;
10 }

AN ORDINARY CLASS, WITH ONE THING TO NOTICE

Ten lines you could have written in Class 14: two private fields and a constructor that fills them.

The word to hold on to is private on line 3. Nothing outside Department can read deptName. Remember that when you reach the next piece — because something is about to read it anyway.

Piece 2 of 3 · a class living inside another class. Fifteen lines, and the surprise is on line 23.

DepartmentDemo.java · PIECE 2 OF 3 — THE INNER CLASS (lines 12–27)
12 class HOD // KIND 2 — no 'static'
13 {
14 String name;
15
16 HOD(String hodName)
17 {
18 name = hodName;
19 }
20
21 void introduce()
22 {
23 System.out.println(name + " heads " + deptName
24 + " (" + studentCount + " students)"); // private fields, read directly
25 }
26 }
27}

LINE 23 SHOULD BE ILLEGAL — BUT IT IS NOT

introduce() prints deptName and studentCount directly. Those are private fields of another class, and no getter was written anywhere in this file.

It works because HOD is inside Department. To Java, an inner class is a member of the outer class — and members can see each other's private parts.

One word makes this possible: the missing static on line 12. That is the entire difference from the previous example.

Piece 3 of 3 · building one. Twelve lines — and line 34 has syntax you have never seen before.

DepartmentDemo.java · PIECE 3 OF 3 — OUTER FIRST, THEN INNER (lines 29–40)
29public class DepartmentDemo
30{
31 public static void main(String[] args)
32 {
33 Department cse = new Department("CSE", 240); // outer FIRST
34 Department.HOD h = cse.new HOD("Dr. Rajesh"); // then inner
35 h.introduce();
36
37 Department ece = new Department("ECE", 180);
38 ece.new HOD("Dr. Latha").introduce(); // different outer → different data
39 }
40}
ECLIPSE CONSOLE · REAL RUN
<terminated> DepartmentDemo [Java Application]
Dr. Rajesh heads CSE (240 students)
Dr. Latha heads ECE (180 students)
Two lines, and the gap between them is the lesson. The introduce() method on line 21 is written once, and it never receives a department as a parameter — yet the first line says CSE/240 and the second says ECE/180. Each HOD object silently carries a link to its own outer Department, and reads that object's private fields through it. No getters were written anywhere in this file.
Line 29, unpacked slowly. ece.new HOD("Dr. Latha").introduce(); does three things in one line: asks ece to create a HOD, then immediately calls introduce() on the result, and never stores the object in a variable. It is legal and common, but if it reads as dense, split it into two lines like 25–26 — there is no behavioural difference.
The mistake almost everyone makes first:

Writing new Department.HOD("Dr. Rajesh") — copying Part 10's syntax onto a non-static inner class. Eclipse replies: an enclosing instance that contains Department.HOD is required. Translate that message into plain English and it says exactly what you learned above: “which department's HOD? I need the department object first.” The fix is always to create the outer object and use outerObj.new Inner().

PART 12 · KIND 3 OF 4 · ss-g227

Local inner — a class that exists
only inside one method

SELF-STUDY PART — READ THIS ONE ON YOUR OWN

Everything you need is on this page — nothing here is examined heavily

This is the rarest of the four kinds in real code, so the course marks it self-study. It is on the page in full, with a complete working program, because it is in the syllabus sentence and you should be able to recognise it. Read it once tonight; you do not need to memorise it.

The idea in one sentence

You already know that a variable declared inside a method is a local variable — it exists only while that method runs, and its name is invisible outside. A local inner class is the same idea applied to a class: declared inside a method's braces, usable only within them, and completely invisible everywhere else.

When is that useful? When you need a small helper for the logic of exactly one method, and letting the rest of the class see it would only invite confusion. It is the narrowest scope Java offers a named class.

ECLIPSE · PACKAGE EXPLORER PATH JavaClass15 / src / (default package) / LocalInnerDemo.java
LocalInnerDemo.java · PIECE 1 OF 2 — THE METHOD WITH A CLASS IN IT (lines 1–20)
1public class LocalInnerDemo
2{
3
4 void printResult(int internal, int external)
5 {
6
7 class Grader // KIND 3 — declared INSIDE a method
8 {
9 String grade()
10 {
11 int t = internal + external; // reads the METHOD's parameters
12 if (t >= 70) return "A";
13 if (t >= 50) return "B";
14 return "C";
15 }
16 }
17
18 Grader g = new Grader(); // used right here, in the same method
19 System.out.println("Total " + (internal + external) + " → grade " + g.grade());
20 }

LOOK WHERE LINE 7 SITS

class Grader is declared inside the braces of printResult — not at the top of the file. That is the whole idea of a local inner class.

Line 11 is the reward: Grader reads internal and external, which are the method's own parameters. No field, no getter, no argument passed in. It simply sees them, because it lives inside the method with them.

Piece 2 of 2 · calling it, and proving the limit. Nine lines, one of them commented out on purpose.

LocalInnerDemo.java · PIECE 2 OF 2 — main(), AND THE LIMIT (lines 22–29)
22 public static void main(String[] args)
23 {
24 LocalInnerDemo d = new LocalInnerDemo();
25 d.printResult(18, 57);
26 d.printResult(12, 30);
27 // Grader x = new Grader(); // ✗ the name does not exist out here
28 }
29}
ECLIPSE CONSOLE · REAL RUN
<terminated> LocalInnerDemo [Java Application]
Total 75 → grade A
Total 42 → grade C
Each call to printResult builds its own Grader and throws it away. Line 27 is commented out because Grader's name genuinely does not exist in main — uncomment it and Eclipse says Grader cannot be resolved to a type. That is the “local” in local inner class, enforced by the compiler.
Line 11 is the interesting one. The nested class reads internal and external — which are the method's parameters, not fields of any class. A local inner class can use the local variables of the method that contains it, provided those variables never change after being set. Java calls such a variable effectively final. You do not need this term for the exam; recognise it if you see it.
PART 13 · KIND 4 OF 4 · g228

Anonymous inner — a class with
no name at all

The last kind is the strangest to look at and the most common in real Java. Once you can read its syntax, a huge amount of professional Java code stops looking like punctuation soup.

Start from the problem, as always

From Class 11 you know an interface is a list of unimplemented methods, and that to use one you write a class that implements it. Now consider a real need: the campus app must react when a student taps “Pay Fees”. You have an interface for that:

THE INTERFACE
interface ClickListener
{
void onClick();
}

To supply behaviour the normal way, you must write a whole named class:

class PayButtonListener implements ClickListener
{
public void onClick()
{
System.out.println("Opening fee payment...");
}
}

That works. But notice what it cost: a whole new named class, used exactly once, for one method with one line inside it. If the app has thirty buttons, you now maintain thirty near-identical classes whose names you must invent and remember.

An anonymous inner class removes that ceremony. It says: “I need an object that implements this interface, I need it right here, and I am never going to refer to its class again — so let me skip naming it.”

HOW TO READ THE SYNTAX — THE BRACE IS THE WHOLE TRICK

Look at these two lines side by side. The only difference is a brace:

// ORDINARY OBJECT — semicolon straight after the round brackets
ClickListener a = new PayButtonListener();
// ANONYMOUS INNER CLASS — a brace pair where the semicolon was
ClickListener b = new ClickListener()
{
public void onClick()
{
System.out.println("Logging out...");
}
};

In the second declaration, new ClickListener() is followed by a brace pair holding a class body instead of by a semicolon. So Java reads it as: “define a brand-new nameless class that implements ClickListener, with this body, and immediately create one object of it.”

The rule to keep: new SomeType() followed by an opening brace is never an ordinary object creation. The brace means a class is being declared on the spot. And note how the block closes — brace on its own line, then a semicolon, because this is still one statement assigning a value.

But Class 11 said you cannot instantiate an interface!

Correct, and that rule is not broken here. new ClickListener() followed by a class body does not create an interface object. It creates an object of a new nameless class that implements ClickListener. The interface name before the brace only says which contract the nameless class fulfils. Being precise about this sentence is worth marks whenever anonymous classes appear in an exam.

THE PROGRAM — BOTH STYLES IN ONE FILE, SO THE SAVING IS VISIBLE

ECLIPSE · PACKAGE EXPLORER PATH JavaClass15 / src / (default package) / ClickDemo.java
ClickDemo.java · PIECE 1 OF 3 — STYLE 1, THE NAMED CLASS (lines 1–21)
1interface ClickListener
2{
3 void onClick(); // one unimplemented method
4}
5
6// ---------- STYLE 1: a named class, the Class-11 way ----------
7class PayButtonListener implements ClickListener
8{
9 public void onClick()
10 {
11 System.out.println("Opening fee payment...");
12 }
13}
14
15public class ClickDemo
16{
17 public static void main(String[] args)
18 {
19
20 ClickListener pay = new PayButtonListener();
21 pay.onClick();

THIS PIECE IS ALL REVISION

Nothing here is new. An interface with one method (lines 1–4), a named class that implements it (lines 7–13), then two lines in main to build it and call it.

Count the cost: a whole named class, plus a line to create it. Keep that count — the next piece does the same job with less.

Piece 2 of 3 · the same job, with no class name at all. This is the new idea, and it is only eight lines.

ClickDemo.java · PIECE 2 OF 3 — STYLE 2, ANONYMOUS (lines 23–31)
23 // ---------- STYLE 2: anonymous inner class ----------
24 ClickListener logout = new ClickListener()
25 { // brace = new nameless class
26 public void onClick()
27 {
28 System.out.println("Logging out of campus Wi-Fi...");
29 }
30 }; // brace THEN semicolon
31 logout.onClick();

READ LINE 24 SLOWLY — IT IS THE WHOLE TRICK

new ClickListener() looks impossible: you cannot build an interface. But then comes an opening brace instead of a semicolon.

That brace means: “invent a nameless class right here that implements ClickListener, and give me one object of it.” The body between the braces is that class.

Line 30 is where marks are lost: }; — brace, then semicolon. Line 24 started a statement, so the statement must be finished.

Piece 3 of 3 · the shortest form of all — created and called on the spot, never stored anywhere.

ClickDemo.java · PIECE 3 OF 3 — USE IT AND FORGET IT (lines 33–41)
33 new ClickListener() // not even stored in a variable
34 {
35 public void onClick()
36 {
37 System.out.println("Refreshing attendance...");
38 }
39 }.onClick(); // created and called at once
40 }
41}
ECLIPSE CONSOLE · REAL RUN
<terminated> ClickDemo [Java Application]
Opening fee payment...
Logging out of campus Wi-Fi...
Refreshing attendance...
Three behaviours, three onClick() implementations — and only one of them needed a named class. Compare the code cost: style 1 spent lines 6–10 plus line 15. Style 2 did the same job in lines 19–24, with no name invented and nothing left in the project for a future reader to wonder about.
Why }; on line 30 and }.onClick(); on line 39. Line 24 began a statement (ClickListener logout = ...), so it must end with a semicolon after the class body closes. Line 33 never assigned anything, so line 39 closes the body and then immediately calls the method on the object just made. Both shapes are common; the semicolon placement is what students most often get wrong.

WHERE YOU WILL MEET THIS AGAIN — TWICE

Class 21 (threads). Starting a thread needs an object implementing Runnable, and it is almost always written anonymously — a new Runnable() with its run() body opened on the spot, handed to new Thread(...), then .start() called on it. When that code appears, you will already be able to read it.

Unit 5 (lambdas). Java 8 noticed that anonymous classes for single-method interfaces are mostly boilerplate, and shortened the whole thing to () -> System.out.println("..."). A lambda is a compressed anonymous inner class — which is why this part, taught now, is the foundation for that one later.

PART 14 · YOUR TURN · c15b-act-01 & c15b-act-02

Two activities — notebook first,
then unlock my answer

Both solution sheets are locked behind a button on purpose. The attempt is where the learning happens; reading my version afterwards is only the correction pass.

Activity 1 · Design a Singleton for the college Wi-Fi login

PROBLEM SOLVING · 10 MIN Design a class CollegeWifiSession that the campus network can trust.

The network's rule, in plain English: one active session per student at a time. Your class must make a second login physically impossible rather than merely discouraged.

Requirements:

  • A private constructor taking a String rollNumber.
  • A static getInstance(String rollNumber) method that returns the session.
  • Called twice with the same roll number, it must return the same object — not a copy.
  • Called with a different roll number while a session is active, it must refuse — print a clear message and return the existing session rather than crashing.
  • A logout() method that clears the session so a different roll number can log in afterwards.

Then answer in one written sentence: why would a plain public constructor make “one session per student” impossible to enforce, no matter how careful the rest of the app is?

Test it with s1 == s2, exactly as Part 6 did. If that prints false for two calls with the same roll number, your Singleton is broken.

Ten minutes in the notebook first — you already have every piece you need.

SOLUTION SHEET · CollegeWifiSession
ECLIPSE · PACKAGE EXPLORER PATH JavaClass15 / src / (default package) / CollegeWifiSessionDemo.java
CollegeWifiSessionDemo.java · PIECE 1 OF 3 — THE GATE (lines 1–25)
1class CollegeWifiSession
2{
3 private static CollegeWifiSession instance; // the ONE slot
4 private final String rollNumber;
5 private int dataUsedMB = 0;
6
7 private CollegeWifiSession(String roll) // PRIVATE
8 {
9 rollNumber = roll;
10 System.out.println("[session opened for " + roll + "]");
11 }
12
13 public static CollegeWifiSession getInstance(String rollNumber)
14 {
15 if (instance == null) // nobody logged in yet
16 {
17 instance = new CollegeWifiSession(rollNumber);
18 }
19 else if (!instance.rollNumber.equals(rollNumber))
20 {
21 System.out.println("REFUSED: " + instance.rollNumber
22 + " is already active. " + rollNumber + " cannot log in.");
23 }
24 return instance;
25 }

ONE NEW IDEA, ON LINE 19

This is the Singleton you already know, plus one extra branch. Line 15 handles “nobody logged in yet”. Line 19 handles the new case: somebody else is already logged in, so this roll number is refused.

That else if is the whole difference between a plain Singleton and a Singleton that enforces a rule.

Why final on line 4? A session's roll number should never change after it opens. final makes that a compiler-enforced fact rather than a hope.

Piece 2 of 3 · ordinary methods, plus the one that resets the gate.

CollegeWifiSessionDemo.java · PIECE 2 OF 3 — USE, STATUS, LOGOUT (lines 27–42)
27 public void use(int mb)
28 {
29 dataUsedMB += mb;
30 }
31
32 public String status()
33 {
34 return rollNumber + " · " + dataUsedMB + " MB";
35 }
36
37 public static void logout() // frees the slot
38 {
39 System.out.println("[logged out]");
40 instance = null;
41 }
42}

LINE 40 IS THE INTERESTING ONE

instance = null; puts the slot back to how it started. The next call to getInstance() will find null again and open a fresh session — which is exactly what logging out of campus Wi-Fi should do.

logout() is static for the same reason getInstance() is: it works on the class's one slot, not on any single object.

Piece 3 of 3 · four scenarios in one run — same student twice, a different student refused, then logout and retry.

CollegeWifiSessionDemo.java · PIECE 3 OF 3 — main() (lines 44–61)
44public class CollegeWifiSessionDemo
45{
46 public static void main(String[] args)
47 {
48 CollegeWifiSession s1 = CollegeWifiSession.getInstance("733-045");
49 s1.use(120);
50
51 CollegeWifiSession s2 = CollegeWifiSession.getInstance("733-045");
52 System.out.println("s1 == s2 ? " + (s1 == s2));
53 s2.use(80);
54 System.out.println("status: " + s1.status());
55
56 CollegeWifiSession.getInstance("733-101"); // different roll
57
58 CollegeWifiSession.logout();
59 CollegeWifiSession.getInstance("733-101"); // now allowed
60 }
61}
ECLIPSE CONSOLE · REAL RUN
<terminated> CollegeWifiSessionDemo [Java Application]
[session opened for 733-045]
s1 == s2 ? true
status: 733-045 · 200 MB
REFUSED: 733-045 is already active. 733-101 cannot log in.
[logged out]
[session opened for 733-101]
Six console lines, and every one is a requirement being proved. Press 28 opened the only session. Press 30 called getInstance again and nothing printed — that silence is the second new being skipped. Press 31 confirms true: one object, two names. Press 33 shows 120 + 80 = 200 through s1, though the 80 was added via s2 — shared state. Press 34 refuses the outsider, and only after logout() nulls the slot does press 36 admit a new roll number.
Why logout() is static. It has to assign instance = null, and instance is a static field belonging to the class, not to any object. Making logout() static keeps that symmetry: getInstance() hands the slot out, logout() clears it, and both speak to the class.
  • LINE 3One private static field is the entire “there can be only one” mechanism. static means one per class; private means nobody outside can reassign it.
  • LINE 7The private constructor. This is what makes the design enforceable instead of merely documented.
  • LINES 15–23Three cases handled: nobody active → create; same roll → return the existing object; different roll → refuse with a message and still return the active session rather than null, so no caller crashes.
  • LINE 40instance = null is what lets a different student log in later. Without it, the first roll number would own the network until the program ended.

THE WRITTEN ANSWER

Why a public constructor makes the rule unenforceable: because with a public constructor, any line of code anywhere in the app can write new CollegeWifiSession("733-101") and get a second live session — and the class has no way to know it happened, let alone stop it. The rule would then depend on every present and future programmer remembering to go through the proper method. A private constructor moves the guarantee from human discipline into the compiler: the wrong code no longer compiles.

Activity 2 · Classify four nested classes

CLASSIFICATION · 5 MIN For each of the four snippets below, name which of the four kinds it is — and write the one detail that gave it away.

Use the table from Part 9 if you need it. Write your four answers down before unlocking.

SNIPPET A
class College
{
static class Address
{
String city;
}
}
SNIPPET B
class Library
{
private int books;
class Shelf
{
int count()
{
return books;
}
}
}
SNIPPET C
void process()
{
class Validator
{
boolean ok()
{
return true;
}
}
new Validator().ok();
}
SNIPPET D
Runnable r = new Runnable()
{
public void run()
{
System.out.println("go");
}
};

Four answers in the notebook first.

SOLUTION SHEET · FOUR KINDS IDENTIFIED
SNIPPETKINDTHE GIVEAWAY
AStatic nested classThe word static on the nested declaration. Created as new College.Address(), with no College object needed.
BMember inner classDeclared directly in the class with no static — and the proof is return books;, reading the outer object's private field. Only a non-static inner class can do that. Needs lib.new Shelf().
CLocal inner classThe class sits inside a method body. Its name Validator does not exist outside process().
DAnonymous inner classNo class name is ever declared — new Runnable() is followed by an opening brace, so a nameless class implementing Runnable is defined and instantiated in one expression. Note that the block closes with a brace then a semicolon.

IF YOU MIXED UP A AND B

That is the mix-up worth fixing tonight, because it is the one exams test. The single word static is the whole difference, and its consequence is the row you were told to memorise in Part 9: can this nested class reach the outer object's instance fields? Snippet B's return books; would be a compile error the moment you added static to class Shelf — with the same “non-static variable cannot be referenced from a static context” message from Class 9.

CLASS 15 · DONE · WHAT YOU CAN NOW DO

Three of the five syllabus items,
closed with working code.

You deepened abstract classes into a hierarchy where the compiler refuses an unfinished subclass. You met Singleton and used a private constructor to make a rule enforceable instead of merely documented. You classified all four kinds of nested class and ran three of them. Two PYQs — P2·Q12(a) and P1·Q4 — are answered in full in your notebook.

Next hour, Class 16 finishes the syllabus sentence: Interface deepened (Java-8 default and static methods, marker interfaces) and Package — how a real Java project is laid out on disk, in Eclipse and on the command line with javac -d. That command is the exact ritual Lab 3 then uses to build a two-package attendance app, so Class 16 is the class that makes Lab 3 straightforward instead of mysterious.

One honest forward note: today's Singleton is not safe if two logins arrive at the same instant. Fixing that needs synchronized and volatile, which arrive at Class 23. We will return to this exact WifiSession then and repair it properly.