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.
THE OFFICIAL SYLLABUS SENTENCE THIS HOUR SERVES
“Classes and Interfaces: Singleton class, Abstract class, Nested class, Interface, Package.”
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
abstractmethod call actually does at runtime across several subclasses.
THE ROAD THROUGH THIS CLASS
Reservation with ReserveTrain and ReserveBus
PYQ P2·Q12a · 4M
private constructor plus a static getInstance() — then broken on purpose
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.
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 IN | THE IDEA | THE SYNTAX | WHY TODAY NEEDS IT |
|---|---|---|---|
| Class 10 | Inheritance — a child class acquires a parent's fields and methods | class Professor extends CollegeStaff | An abstract class is only useful as a parent. No inheritance, no point. |
| Class 11 | Overriding — a child rewrites a method it inherited | same name, same parameters, in the child | Completing an abstract method is overriding. Same rules apply. |
| Class 11 | Runtime polymorphism — a parent-typed variable can hold a child object, and the child's method runs | CollegeStaff s = new Professor(); | This is the whole payoff. Without it an abstract class is just a rule-book nobody reads. |
| Class 11 | abstract means “incomplete — cannot be instantiated” | abstract class CollegeStaff | Today that one-line definition grows into six enforceable rules. |
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:
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
PACKAGE EXPLORER
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.
class CollegeStaff{ String name; CollegeStaff(String staffName) { name = staffName; } double calculateSalary() { return 0; // the parent has to invent something }}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.
class Professor extends CollegeStaff{ int lectures; Professor(String staffName, int lectureCount) { super(staffName); lectures = lectureCount; } double calculateSalary() { return lectures * 1200; }}class LabAssistant extends CollegeStaff{ int hours; LabAssistant(String staffName, int hoursWorked) { super(staffName); hours = hoursWorked; } // we FORGOT calculateSalary() — and nothing complains}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.
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.
public class BrokenStaff{ public static void main(String[] args) { CollegeStaff a = new Professor("Sridevi", 40); CollegeStaff b = new LabAssistant("Ramesh", 90); System.out.println(a.name + " salary = " + a.calculateSalary()); System.out.println(b.name + " salary = " + b.calculateSalary()); }}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.
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.”
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.
Two places the word appears, and one punctuation mark that surprises everybody:
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.
The whole idea fits in six lines. Nothing else is needed to see it work:
new Square() is legal — Square is complete. new Shape() is a compile error — Shape has a hole in it.
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.
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:
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
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.
PACKAGE EXPLORER
RIGHT-CLICK src › New › Class › name it StaffPayrollDemo › tick public static void main › Finish. 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.
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:
- Piece 1 —
CollegeStaff's ordinary half: two fields, a constructor, two getters. - Piece 2 — the same class's promise, plus one finished method that uses it.
- Piece 3 —
Professor, the first class to keep the promise. - Piece 4 —
LabAssistant, keeping it a second way. - Piece 5 —
Librarian, keeping it a third way. - Piece 6 —
main(), 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.
abstract class CollegeStaff{ private String name; private String staffId; CollegeStaff(String staffName, String idCode) { name = staffName; staffId = idCode; } public String getName() { return name; } public String getStaffId() { return staffId; }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.
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.
// PROMISE: every staff member has a salary rule. // I refuse to guess what it is. No body — just a semicolon. public abstract double calculateSalary(); // a NORMAL method — abstract classes may be partly complete public void printPayslip() { System.out.printf("%-10s %-7s Rs %10.2f%n", name, staffId, calculateSalary()); }}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.
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.
class Professor extends CollegeStaff{ private int lectures; Professor(String staffName, String idCode, int lectureCount) { super(staffName, idCode); lectures = lectureCount; } public double calculateSalary() // keeps the promise { return lectures * 1200.0; }}Professor is a complete class and new Professor(...) is legal.
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.
class LabAssistant extends CollegeStaff{ private int hours; LabAssistant(String staffName, String idCode, int hoursWorked) { super(staffName, idCode); hours = hoursWorked; } public double calculateSalary() { return hours * 180.0; }}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.
class Librarian extends CollegeStaff{ private double monthlyPay; Librarian(String staffName, String idCode, double pay) { super(staffName, idCode); monthlyPay = pay; } public double calculateSalary() { return monthlyPay; }}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.
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.
public class StaffPayrollDemo{ public static void main(String[] args) { CollegeStaff[] payroll = { new Professor("Sridevi", "VCE101", 40), new LabAssistant("Ramesh", "VCE102", 90), new Librarian("Anitha", "VCE103", 32000) }; System.out.println("---- VCE PAYROLL ----"); for (CollegeStaff s : payroll) { s.printPayslip(); // same call, three different rules } }}if for the new Librarian type; the loop simply worked.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 RULE | WHY IT IS TRUE | PROVED BY |
|---|---|---|
| An abstract class cannot be instantiated | An 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 constructor | It 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 fields | Only 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 abstract | Otherwise 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 itself | The 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 final | Each 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 final — final 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.
CollegeStaff s = new CollegeStaff("A", "V1");
Trying to create the abstract class itself.
abstract class Fee { double amount; }
An abstract class with no abstract method at all.
class Fee { abstract void collect(); }
An abstract method inside a class that is not abstract.
abstract void collect()
Marked abstract, then given an empty pair of braces as its body instead of a semicolon.
abstract class Casual extends CollegeStaff
A subclass with an empty body that does not override calculateSalary() — but is itself abstract.
Rows 1 and 6 are the two that separate the students who understand abstract from the ones who memorised “cannot create object”.
Reservation class with two subclasses. We will answer it completely, in the examiner's own words.
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.
Reservation that contains an abstract method reserve(). Create two subclasses ReserveTrain and ReserveBus that implement the reserve() method to display appropriate messages.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.abstract 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)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.
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.
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.
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 them — ReserveTrain, capital R, capital T, no space, no underscore. Examiners do notice.
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.
Write the public class with main. Create one object of each subclass and call reserve() on each. Declare the variables using the parent type — Reservation r1 = new ReserveTrain(); — because that demonstrates runtime polymorphism and it is the version an examiner is hoping to see.
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.
PACKAGE EXPLORER
RIGHT-CLICK src › New › Class › name it ReservationDemo › tick public static void main › Finish. 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.
// PYQ Paper 2 · Q12(a) · 4 marksabstract class Reservation{ // the PROMISE: no body, ends in a semicolon abstract void reserve();}class ReserveTrain extends Reservation{ void reserve() // promise kept { System.out.println("Train seat reserved: Kacheguda - Tirupati, coach S4, berth 32."); }}class ReserveBus extends Reservation{ void reserve() // promise kept, differently { System.out.println("Bus seat reserved: Hyderabad - Vijayawada, seat 14, window."); }}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 implements — Reservation is a class, not an interface.
Piece 2 of 2 · main(). Thirteen lines that earn the rest of the marks.
public class ReservationDemo{ public static void main(String[] args) { // parent-typed reference, child object — runtime polymorphism Reservation r1 = new ReserveTrain(); Reservation r2 = new ReserveBus(); r1.reserve(); // runs ReserveTrain's body r2.reserve(); // runs ReserveBus's body }}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.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.
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
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
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:
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
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.
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.
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.
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.
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.
TrainReservation instead of ReserveTrain, or bookSeat() instead of reserve(). The question printed exact names; changing them costs marks for no benefit at all.
Parent says public abstract void reserve();, child says void reserve(). Real error: attempting to assign weaker access privileges. Keep the modifiers matching.
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.
new at all. We start, as always, with the problem: two Wi-Fi sessions for one roll number.
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:
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.dataUsed is a single truthful number. Note that nobody wrote new.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.
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).
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.
The complete shape, three ingredients, in this order. This is the skeleton to memorise:
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.
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 ofWifiSessionitself —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.
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.
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:
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.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
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.
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.
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.
PACKAGE EXPLORER
RIGHT-CLICK src › New › Class › name it WifiSessionDemo › tick public static void main › Finish. 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.
class WifiSession{ // INGREDIENT 1 — the single object, held by the CLASS itself private static WifiSession instance; // ordinary per-object state — there will be only one object, // so these are effectively the whole app's session data private String rollNo = "(not logged in)"; private int dataUsedMB = 0; // INGREDIENT 2 — PRIVATE constructor: nobody outside can say `new` private WifiSession() { System.out.println("[WifiSession object created — happens once]"); } // INGREDIENT 3 — the ONLY public way in. static, so no object needed. public static WifiSession getInstance() { if (instance == null) // true ONLY on the first call { instance = new WifiSession(); // legal: we are inside the class } return instance; // same object, every time }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.
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.
// normal encapsulated behaviour (Class 14) public void login(String newRollNo) { rollNo = newRollNo; dataUsedMB = 0; } public void use(int mb) { if (mb > 0) dataUsedMB += mb; } public void status() { System.out.println("roll=" + rollNo + " data=" + dataUsedMB + " MB"); }}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.
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.
public class WifiSessionDemo{ public static void main(String[] args) { System.out.println("-- login screen asks for the session --"); WifiSession s1 = WifiSession.getInstance(); s1.login("1602-24-733-101"); s1.use(120); System.out.println("-- settings screen asks for the session --"); WifiSession s2 = WifiSession.getInstance(); s2.use(80); System.out.print("s1 == s2 ? "); System.out.println(s1 == s2); System.out.print("via s1: "); s1.status(); System.out.print("via s2: "); s2.status(); }}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.println there — but for learning, and for a viva, it is the clearest possible evidence.
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:
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.
ifs1 == 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.staticnon-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?
new
Field kept private static but getInstance() made public static WifiSession getInstance() returning new WifiSession() directly
Never touches instance at all.
s1 == s2 is false
Field made public static WifiSession instance;
Constructor still private, getInstance() still correct.
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.
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.
| INGREDIENT | WHAT IT PREVENTS | REMOVE IT AND… |
|---|---|---|
private constructor | Outsiders creating objects with new | compiles, but anyone can make unlimited objects — not a Singleton |
private static field | The object being lost between calls, and outsiders resetting it | either a compile error (if static goes) or a resettable Singleton (if private goes) |
public static method | The class becoming unreachable | no way to obtain the object at all — the class is dead |
if (instance == null) | A second object being built on the second call | compiles 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.
“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.
private — accessible within the same class (Class 13) · constructors (Class 8) · static members (Class 9) · the Singleton pattern (Parts 5–6, today)private 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.
PAPER 1 · Q4 · ONE BORDER, TWO ARROWS — THE ANSWER IS WHICH ONE CROSSES
Step-by-step: how to build a 2-mark answer
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.
State the meaning of private precisely: accessible only within the same class. This one clause is the justification — everything else follows from it.
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().
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.
class Config{ private static Config instance; private String collegeName = "Vasavi College of Engineering"; private Config() // PRIVATE constructor { System.out.println("Config object built INSIDE the class."); } public static Config getInstance() { if (instance == null) { instance = new Config(); // LEGAL — same class } return instance; } public String getCollegeName() { return collegeName; }}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.
public class PrivateCtorProof{ public static void main(String[] args) { // Config c = new Config(); // ← would NOT compile Config c = Config.getInstance(); // this works System.out.println("Instance exists? " + (c != null)); System.out.println("College: " + c.getCollegeName()); }}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.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
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.
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
The instinctive answer, and it loses both marks at once. It comes from reading private as “switched off” rather than “internal only”.
The question printed the words justify your answer. A bare “Yes” is worth about half a mark. The reasoning is the question.
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.
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.
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 == null→ true. 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 initialisation — private 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.
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:
MarkEntry exists only to serve MarksSheet, but nothing in the code says so. A new developer sees two unrelated classes and has to guess.
MarkEntry is visible to the entire package. Anybody can use it for anything, including in ways that make no sense without a marks sheet.
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.
FOUR KINDS · ONE SPLIT THAT MATTERS: static OR NOT
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.
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.
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.
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 NESTED | MEMBER INNER | LOCAL INNER | ANONYMOUS | |
|---|---|---|---|---|
| Declared where? | in the class, with static | in the class, no static | inside a method | inside an expression |
| Has a name? | yes | yes | yes | NO |
| Needs an outer object? | NO | yes | yes* | yes* |
| Can it use outer instance fields? | NO | yes | yes | yes |
| How you create it | new Outer.Inner() | outerObj.new Inner() | new Inner() in the method | new Type() followed by a class body in braces |
| Taught in | Part 10 | Part 11 | Part 12 (self-study) | Part 13 |
*unless the enclosing method is itself static, in which case there is no outer object to attach to.
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.
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
Write a normal class, but put it inside another class's braces and mark it static:
Use the outer class's name like a folder path. No ExamResult object is created anywhere — look carefully, there is only one new:
This is the line that proves the rule. If the nested class needed an outer object, this line would be impossible.
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
class ExamResult{ String studentName = "Sneha"; // INSTANCE field of the outer class static class Marks // KIND 1 — static nested { int internal; int external; int total() { return internal + external; } // ✗ the four lines below would NOT compile here: // int bad() // { // return studentName.length(); // } }}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.
Piece 2 of 2 · using it. Twelve lines — and line 26 is the one to memorise.
public class ExamResultDemo{ public static void main(String[] args) { ExamResult.Marks m = new ExamResult.Marks(); m.internal = 18; m.external = 57; System.out.println("Internal : " + m.internal); System.out.println("External : " + m.external); System.out.println("Total : " + m.total()); }}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.
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? | NO — new Outer.Inner() | YES — outerObj.new Inner() |
| Can read outer instance fields? | NO — compile error | YES — even private ones |
| So it is useful when… | the helper is self-contained | the 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
class Department{ private String deptName; // PRIVATE — sealed from outside private int studentCount; Department(String branch, int strength) { deptName = branch; studentCount = strength; }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.
class HOD // KIND 2 — no 'static' { String name; HOD(String hodName) { name = hodName; } void introduce() { System.out.println(name + " heads " + deptName + " (" + studentCount + " students)"); // private fields, read directly } }}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.
public class DepartmentDemo{ public static void main(String[] args) { Department cse = new Department("CSE", 240); // outer FIRST Department.HOD h = cse.new HOD("Dr. Rajesh"); // then inner h.introduce(); Department ece = new Department("ECE", 180); ece.new HOD("Dr. Latha").introduce(); // different outer → different data }}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.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.
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().
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.
public class LocalInnerDemo{ void printResult(int internal, int external) { class Grader // KIND 3 — declared INSIDE a method { String grade() { int t = internal + external; // reads the METHOD's parameters if (t >= 70) return "A"; if (t >= 50) return "B"; return "C"; } } Grader g = new Grader(); // used right here, in the same method System.out.println("Total " + (internal + external) + " → grade " + g.grade()); }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.
public static void main(String[] args) { LocalInnerDemo d = new LocalInnerDemo(); d.printResult(18, 57); d.printResult(12, 30); // Grader x = new Grader(); // ✗ the name does not exist out here }}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.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.
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:
To supply behaviour the normal way, you must write a whole named class:
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:
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.
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
interface ClickListener{ void onClick(); // one unimplemented method}// ---------- STYLE 1: a named class, the Class-11 way ----------class PayButtonListener implements ClickListener{ public void onClick() { System.out.println("Opening fee payment..."); }}public class ClickDemo{ public static void main(String[] args) { ClickListener pay = new PayButtonListener(); 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.
// ---------- STYLE 2: anonymous inner class ---------- ClickListener logout = new ClickListener() { // brace = new nameless class public void onClick() { System.out.println("Logging out of campus Wi-Fi..."); } }; // brace THEN semicolon 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.
new ClickListener() // not even stored in a variable { public void onClick() { System.out.println("Refreshing attendance..."); } }.onClick(); // created and called at once }}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.}; 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.
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
privateconstructor taking aString 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.
class CollegeWifiSession{ private static CollegeWifiSession instance; // the ONE slot private final String rollNumber; private int dataUsedMB = 0; private CollegeWifiSession(String roll) // PRIVATE { rollNumber = roll; System.out.println("[session opened for " + roll + "]"); } public static CollegeWifiSession getInstance(String rollNumber) { if (instance == null) // nobody logged in yet { instance = new CollegeWifiSession(rollNumber); } else if (!instance.rollNumber.equals(rollNumber)) { System.out.println("REFUSED: " + instance.rollNumber + " is already active. " + rollNumber + " cannot log in."); } return instance; }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.
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.
public void use(int mb) { dataUsedMB += mb; } public String status() { return rollNumber + " · " + dataUsedMB + " MB"; } public static void logout() // frees the slot { System.out.println("[logged out]"); instance = null; }}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.
public class CollegeWifiSessionDemo{ public static void main(String[] args) { CollegeWifiSession s1 = CollegeWifiSession.getInstance("733-045"); s1.use(120); CollegeWifiSession s2 = CollegeWifiSession.getInstance("733-045"); System.out.println("s1 == s2 ? " + (s1 == s2)); s2.use(80); System.out.println("status: " + s1.status()); CollegeWifiSession.getInstance("733-101"); // different roll CollegeWifiSession.logout(); CollegeWifiSession.getInstance("733-101"); // now allowed }}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.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 staticfield is the entire “there can be only one” mechanism.staticmeans one per class;privatemeans nobody outside can reassign it. - LINE 7The
privateconstructor. 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 40
instance = nullis 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.
Four answers in the notebook first.
| SNIPPET | KIND | THE GIVEAWAY |
|---|---|---|
| A | Static nested class | The word static on the nested declaration. Created as new College.Address(), with no College object needed. |
| B | Member inner class | Declared 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(). |
| C | Local inner class | The class sits inside a method body. Its name Validator does not exist outside process(). |
| D | Anonymous inner class | No 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.