OOP Advanced
Inner Classes
Classes Within Classes
Your LinkedList needs a Node class, but Node has no meaning outside LinkedList. Inner classes let you define classes inside other classes - encapsulating helpers and keeping related code together.
Member inner class
Define a class inside another class with access to outer members.
// Member Inner Class
class OuterClass {
private String name;
private int count = 0;
OuterClass(String name) {
this.name = name;
}
// Member inner class
class InnerClass {
private String innerName;
InnerClass(String innerName) {
this.innerName = innerName;
}
void display() {
// Can access outer's private members!
System.out.println("Outer name: " + name);
System.out.println("Inner name: " + innerName);
System.out.println("Count: " + count);
}
void incrementCount() {
count++; // Can modify outer's fields
}
// Access outer class reference
void showOuterReference() {
System.out.println("Outer this: " + OuterClass.this);
}
}
// Method that uses inner class
void demo() {
InnerClass inner = new InnerClass("demo-inner");
inner.display();
}
public int getCount() {
return count;
}
}
// Another example: linked list with node as inner class
class SimpleList<T> {
private Node head;
private int size = 0;
// Node is implementation detail - hide it
private class Node {
T data;
Node next;
Node(T data) {
this.data = data;
this.next = null;
}
}
public void add(T item) {
Node newNode = new Node(item);
if (head == null) {
head = newNode;
} else {
Node current = head;
while (current.next != null) {
current = current.next;
}
current.next = newNode;
}
size++; // Inner class indirectly affects outer
}
public void printAll() {
Node current = head;
while (current != null) {
System.out.print(current.data + " -> ");
Node next = current.next;
current = next;
}
System.out.println("null");
}
public int size() {
return size;
}
}
public class MemberInner {
public static void main(String[] args) {
System.out.println("=== Member Inner Class ===\n");
// Create outer class instance
OuterClass outer = new OuterClass("MyOuter");
// Create inner class instance
OuterClass.InnerClass inner = outer.new InnerClass("MyInner");
inner.display();
System.out.println("\n--- Modifying Outer from Inner ---");
System.out.println("Count before: " + outer.getCount());
inner.incrementCount();
inner.incrementCount();
System.out.println("Count after: " + outer.getCount());
System.out.println("\n--- Outer Reference ---");
inner.showOuterReference();
System.out.println("\n=== Linked List Example ===");
SimpleList<String> list = new SimpleList<>();
list.add("Apple");
list.add("Banana");
list.add("Cherry");
System.out.println("Size: " + list.size());
list.printAll();
// Node class is hidden - cannot access from here
// SimpleList.Node node = ...; // COMPILE ERROR!
System.out.println("\n=== Member Inner Class Rules ===");
System.out.println("""
1. Has access to ALL outer class members (including private)
2. Can modify outer class fields
3. Requires outer class instance to exist
4. Use OuterClass.this to reference outer instance
5. Create via: outer.new InnerClass()
6. From outside: OuterClass.InnerClass type name
""");
}
}
public static void main(String[] args)
92public class MemberInner {93 public static void main(String[] args) {94 System.out.println("=== Member Inner Class ===\n");95 96 // Create outer class instance //?createouter97 OuterClass outer = new OuterClass("MyOuter");output=== Member Inner Class ===this.name ← MyOuter
7OuterClass(String nameMyOuter) {8 this.name→ MyOuter = nameMyOuter;9}outer ← ⟨OuterClass A⟩
96// Create outer class instance //?createouter97OuterClass outer→ ⟨OuterClass A⟩ = new OuterClass("MyOuter");9899// Create inner class instance //?createinner100OuterClass.InnerClass inner = outer.new InnerClass("MyInner"); //?innercreationthis.innerName ← MyInner
15InnerClass(String innerNameMyInner) {16 this.innerName→ MyInner = innerNameMyInner;17}inner ← ⟨OuterClass$InnerClass B⟩
99// Create inner class instance //?createinner100OuterClass.InnerClass inner→ ⟨OuterClass$InnerClass B⟩ = outer.new InnerClass("MyInner"); //?innercreation101102inner.display();void display()
19void display() {20 // Can access outer's private members! //?accessprivate21 System.out.println("Outer name: " + nameMyOuter);22 System.out.println("Inner name: " + innerNameMyInner);23 System.out.println("Count: " + count0);24}outputOuter name: MyOuter Inner name: MyInner Count: 0inner.display();
102inner.display();103104System.out.println("\n--- Modifying Outer from Inner ---");105System.out.println("Count before: " + outer.getCount());106inner.incrementCount();output --- Modifying Outer from Inner ---public int getCount()
pass 1 of 242public int getCount() {43 return count0;44}System.out.println("Count before: " + outer.getCount());
104System.out.println("\n--- Modifying Outer from Inner ---");105System.out.println("Count before: " + outer.getCount());106inner.incrementCount();107inner.incrementCount();outputCount before: 0count ← 1
pass 1 of 226void incrementCount() { //?modifyouter27 count→ 1++; // Can modify outer's fields28}inner.incrementCount();
105System.out.println("Count before: " + outer.getCount());106inner.incrementCount();107inner.incrementCount();108System.out.println("Count after: " + outer.getCount());count ← 2
pass 2 of 226void incrementCount() { //?modifyouter27 count→ 2++; // Can modify outer's fields28}inner.incrementCount();
106inner.incrementCount();107inner.incrementCount();108System.out.println("Count after: " + outer.getCount());public int getCount()
pass 2 of 242public int getCount() {43 return count2;44}System.out.println("Count after: " + outer.getCount());
107inner.incrementCount();108System.out.println("Count after: " + outer.getCount());109110System.out.println("\n--- Outer Reference ---");111inner.showOuterReference();outputCount after: 2 --- Outer Reference ---void showOuterReference()
30// Access outer class reference //?outerreference31void showOuterReference() {32 System.out.println("Outer this: " + OuterClass.this); //?outerthis33}outputOuter this: ⟨OuterClass A⟩list ← ⟨SimpleList C⟩
110System.out.println("\n--- Outer Reference ---");111inner.showOuterReference();112113System.out.println("\n=== Linked List Example ===");114SimpleList<String> list→ ⟨SimpleList C⟩ = new SimpleList<>();115list.add("Apple");116list.add("Banana");output === Linked List Example ===public void add(T item)
pass 1 of 363public void add(T itemApple) { //?addmethod64 Node newNode = new Node(item);65 if (head == null) {All 3 passes — pass 1 is the card above pass item1 Apple 2 Banana 3 Cherry this.data ← Apple, this.next ← null
pass 1 of 357Node(T dataApple) {58 this.data→ Apple = dataApple;59 this.next→ null = null;60}All 3 passes — pass 1 is the card above pass datathis.datathis.next1 Apple Apple null 2 Banana Banana null 3 Cherry Cherry null newNode ← ⟨SimpleList$Node D⟩
63public void add(T item) { //?addmethod64 Node newNode→ ⟨SimpleList$Node D⟩ = new Node(item);65 if (head == null) {head ← ⟨SimpleList$Node D⟩
64Node newNode = new Node(item);65if (headnull == null) {66 head→ ⟨SimpleList$Node D⟩ = newNode⟨SimpleList$Node D⟩;67} else {size ← 1
73 }74 size→ 1++; // Inner class indirectly affects outer75}list.add("Apple");
114SimpleList<String> list = new SimpleList<>();115list.add("Apple");116list.add("Banana");117list.add("Cherry");newNode ← ⟨SimpleList$Node E⟩
63public void add(T item) { //?addmethod64 Node newNode→ ⟨SimpleList$Node E⟩ = new Node(item);65 if (head == null) {current ← ⟨SimpleList$Node D⟩, current.next ← ⟨SimpleList$Node E⟩
pass 1 of 266 head = newNode;67} else {68 Node current→ ⟨SimpleList$Node D⟩ = head;69 while (current.next != null) {70 current = current.next;71 }72 current.next→ ⟨SimpleList$Node E⟩ = newNode⟨SimpleList$Node E⟩;73}size ← 2
73 }74 size→ 2++; // Inner class indirectly affects outer75}list.add("Banana");
115list.add("Apple");116list.add("Banana");117list.add("Cherry");newNode ← ⟨SimpleList$Node F⟩
63public void add(T item) { //?addmethod64 Node newNode→ ⟨SimpleList$Node F⟩ = new Node(item);65 if (head == null) {current ← ⟨SimpleList$Node D⟩
pass 2 of 266 head = newNode;67} else {68 Node current→ ⟨SimpleList$Node D⟩ = head;69 while (current.next != null) {current.next ← null, current ← ⟨SimpleList$Node E⟩
68Node current = head;69while (current.next⟨SimpleList$Node E⟩ != null) {70 current→ ⟨SimpleList$Node E⟩ = current.next→ null;71}current.next ← ⟨SimpleList$Node F⟩, current ← ⟨SimpleList$Node E⟩
71 }72 current.next→ ⟨SimpleList$Node F⟩ = newNode⟨SimpleList$Node F⟩;73}values this step⟨SimpleList$Node E⟩currentsize ← 3
73 }74 size→ 3++; // Inner class indirectly affects outer75}list.add("Cherry");
116list.add("Banana");117list.add("Cherry");118119System.out.println("Size: " + list.size());120list.printAll();public int size()
87public int size() {88 return size3;89}System.out.println("Size: " + list.size());
119System.out.println("Size: " + list.size());120list.printAll();121// Node class is hidden - cannot access from hereoutputSize: 3current ← ⟨SimpleList$Node D⟩
77public void printAll() {78 Node current→ ⟨SimpleList$Node D⟩ = head;79 while (current != null) {next ← ⟨SimpleList$Node E⟩, current ← ⟨SimpleList$Node E⟩
pass 1 of 378Node current = head;79while (current⟨SimpleList$Node D⟩ != null) {80 System.out.print(current.dataApple + " -> ");81 Node next→ ⟨SimpleList$Node E⟩ = current.next⟨SimpleList$Node E⟩;82 current→ ⟨SimpleList$Node E⟩ = next⟨SimpleList$Node E⟩;83}outputApple ->All 3 passes — pass 1 is the card above pass current.datacurrent.nextnextcurrent1 Apple ⟨SimpleList$Node E⟩ ⟨SimpleList$Node E⟩ ⟨SimpleList$Node D⟩ → ⟨SimpleList$Node E⟩ 2 Banana ⟨SimpleList$Node F⟩ ⟨SimpleList$Node F⟩ ⟨SimpleList$Node E⟩ → ⟨SimpleList$Node F⟩ 3 Cherry null null ⟨SimpleList$Node F⟩ → null System.out.println("null");
83 }84 System.out.println("null");85}outputnulllist.printAll();
119 System.out.println("Size: " + list.size());120 list.printAll();121 // Node class is hidden - cannot access from here122 // SimpleList.Node node = ...; // COMPILE ERROR!123 124 System.out.println("\n=== Member Inner Class Rules ===");125 System.out.println("""126 1. Has access to ALL outer class members (including private)127 2. Can modify outer class fields128 3. Requires outer class instance to exist129 4. Use OuterClass.this to reference outer instance130 5. Create via: outer.new InnerClass()131 6. From outside: OuterClass.InnerClass type name132 """);133}output === Member Inner Class Rules === 1. Has access to ALL outer class members (including private) 2. Can modify outer class fields 3. Requires outer class instance to exist 4. Use OuterClass.this to reference outer instance 5. Create via: outer.new InnerClass() 6. From outside: OuterClass.InnerClass type name
Member inner class can access all of outer's fields, even private ones.
Static nested class
A nested class that doesn't need an outer instance.
// Static Nested Class
class Calculator {
private static final double PI = 3.14159;
private double lastResult; // Instance field
Calculator() {
this.lastResult = 0;
}
// Static nested class
static class MathUtils {
// Can access outer's static members
static double circleArea(double radius) {
return PI * radius * radius; // Uses outer's PI
}
static double square(double n) {
return n * n;
}
static double cube(double n) {
return n * n * n;
}
// Cannot access outer's instance members
// void showLastResult() {
// System.out.println(lastResult); // ERROR!
// }
}
// Static nested class for configuration
static class Config {
private int precision;
private boolean useRadians;
Config() {
this.precision = 2;
this.useRadians = false;
}
Config(int precision, boolean useRadians) {
this.precision = precision;
this.useRadians = useRadians;
}
public int getPrecision() { return precision; }
public boolean isUseRadians() { return useRadians; }
@Override
public String toString() {
return "Config{precision=" + precision + ", radians=" + useRadians + "}";
}
}
public double calculate(double a, double b) {
lastResult = a + b;
return lastResult;
}
public double getLastResult() {
return lastResult;
}
}
// Builder pattern with static nested class
class Pizza {
private final String size;
private final String crust;
private final boolean cheese;
private final boolean pepperoni;
private final boolean mushrooms;
private final boolean onions;
// Private constructor - use builder
private Pizza(Builder builder) {
this.size = builder.size;
this.crust = builder.crust;
this.cheese = builder.cheese;
this.pepperoni = builder.pepperoni;
this.mushrooms = builder.mushrooms;
this.onions = builder.onions;
}
// Static nested Builder class
static class Builder {
// Required parameters
private final String size;
// Optional parameters with defaults
private String crust = "regular";
private boolean cheese = true;
private boolean pepperoni = false;
private boolean mushrooms = false;
private boolean onions = false;
public Builder(String size) {
this.size = size;
}
public Builder crust(String crust) {
this.crust = crust;
return this; // Return this for chaining
}
public Builder pepperoni() {
this.pepperoni = true;
return this;
}
public Builder mushrooms() {
this.mushrooms = true;
return this;
}
public Builder onions() {
this.onions = true;
return this;
}
public Builder noCheese() {
this.cheese = false;
return this;
}
public Pizza build() {
return new Pizza(this);
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(size).append(" pizza, ").append(crust).append(" crust");
if (cheese) sb.append(", cheese");
if (pepperoni) sb.append(", pepperoni");
if (mushrooms) sb.append(", mushrooms");
if (onions) sb.append(", onions");
return sb.toString();
}
}
public class StaticNested {
public static void main(String[] args) {
System.out.println("=== Static Nested Class ===\n");
// Use static nested class directly
double area = Calculator.MathUtils.circleArea(5);
System.out.println("Circle area (r=5): " + area);
System.out.println("Square of 7: " + Calculator.MathUtils.square(7));
System.out.println("Cube of 3: " + Calculator.MathUtils.cube(3));
// Create instance of static nested class
Calculator.Config config = new Calculator.Config(4, true);
System.out.println("\nConfig: " + config);
// No outer instance needed!
Calculator.Config defaultConfig = new Calculator.Config();
System.out.println("Default config: " + defaultConfig);
System.out.println("\n=== Builder Pattern ===");
// Use builder to create Pizza
Pizza pizza1 = new Pizza.Builder("large")
.crust("thin")
.pepperoni()
.mushrooms()
.build();
System.out.println("Pizza 1: " + pizza1);
Pizza pizza2 = new Pizza.Builder("medium")
.pepperoni()
.onions()
.noCheese()
.build();
System.out.println("Pizza 2: " + pizza2);
Pizza pizza3 = new Pizza.Builder("small").build(); // Minimal
System.out.println("Pizza 3: " + pizza3);
System.out.println("\n=== Static vs Member Inner Class ===");
System.out.println("""
Static Nested Class:
- Declared with 'static' keyword
- Can only access outer's static members
- Does NOT need outer instance
- Create via: new Outer.Nested()
- Like a top-level class, just namespaced
Member Inner Class:
- No 'static' keyword
- Can access ALL outer members
- REQUIRES outer instance
- Create via: outer.new Inner()
When to use static nested:
- Builder pattern
- Helper classes that don't need outer state
- Grouping related classes
- Entry types for collections
""");
}
}
public static void main(String[] args)
143public class StaticNested {144 public static void main(String[] args) {145 System.out.println("=== Static Nested Class ===\n");146 147 // Use static nested class directly //?usedirect148 double area = Calculator.MathUtils.circleArea(5); //?calldirect149 System.out.println("Circle area (r=5): " + area);output=== Static Nested Class ===static double circleArea(double radius)
13// Can access outer's static members //?accessstatic14static double circleArea(double radius5.0) {15 return PI * radius5.0 * radius; // Uses outer's PI16}area ← 78.53975
147// Use static nested class directly //?usedirect148double area→ 78.53975 = Calculator.MathUtils.circleArea(5); //?calldirect149System.out.println("Circle area (r=5): " + area78.53975);150System.out.println("Square of 7: " + Calculator.MathUtils.square(7));151System.out.println("Cube of 3: " + Calculator.MathUtils.cube(3));outputCircle area (r=5): 78.53975static double square(double n)
18static double square(double n7.0) {19 return n7.0 * n;20}System.out.println("Square of 7: " + Calculator.MathUtils.square(7));
149System.out.println("Circle area (r=5): " + area);150System.out.println("Square of 7: " + Calculator.MathUtils.square(7));151System.out.println("Cube of 3: " + Calculator.MathUtils.cube(3));outputSquare of 7: 49.0static double cube(double n)
22static double cube(double n3.0) {23 return n3.0 * n * n;24}System.out.println("Cube of 3: " + Calculator.MathUtils.cube(3));
150System.out.println("Square of 7: " + Calculator.MathUtils.square(7));151System.out.println("Cube of 3: " + Calculator.MathUtils.cube(3));152153// Create instance of static nested class //?createinstance154Calculator.Config config = new Calculator.Config(4, true); //?configinstance155System.out.println("\nConfig: " + config);outputCube of 3: 27.0this.precision ← 4, this.useRadians ← true
42Config(int precision4, boolean useRadianstrue) {43 this.precision→ 4 = precision4;44 this.useRadians→ true = useRadianstrue;45}config ← Config{precision=4, radians=true}
153// Create instance of static nested class //?createinstance154Calculator.Config config→ Config{precision=4, radians=true} = new Calculator.Config(4, true); //?configinstance155System.out.println("\nConfig: " + configConfig{precision=4, radians=true});156157// No outer instance needed! //?noouter158Calculator.Config defaultConfig = new Calculator.Config();159System.out.println("Default config: " + defaultConfig);output Config: Config{precision=4, radians=true}this.precision ← 2, this.useRadians ← false
37Config() {38 this.precision→ 2 = 2;39 this.useRadians→ false = false;40}defaultConfig ← Config{precision=2, radians=false}
157// No outer instance needed! //?noouter158Calculator.Config defaultConfig→ Config{precision=2, radians=false} = new Calculator.Config();159System.out.println("Default config: " + defaultConfigConfig{precision=2, radians=false});160161System.out.println("\n=== Builder Pattern ===");162163// Use builder to create Pizza //?usebuilder164Pizza pizza1 = new Pizza.Builder("large") //?fluent165 .crust("thin")166 .pepperoni()167 .mushrooms()168 .build();169System.out.println("Pizza 1: " + pizza1);outputDefault config: Config{precision=2, radians=false} === Builder Pattern ===this.size ← large
pass 1 of 397public Builder(String sizelarge) { //?builderconstructor98 this.size→ large = sizelarge;99}All 3 passes — pass 1 is the card above pass sizecrustthis.sizethis.crustthis.pepperonithis.mushroomsthis.onionsthis.cheese1 large thin large thin true true — — 2 medium — medium — true — true false 3 small — small — — — — — this.crust ← thin
101public Builder crust(String crustthin) { //?crustmethod102 this.crust→ thin = crustthin;103 return this; // Return this for chaining104}this.pepperoni ← true
pass 1 of 2106public Builder pepperoni() { //?toppingmethod107 this.pepperoni→ true = true;108 return this;109}this.mushrooms ← true
111public Builder mushrooms() {112 this.mushrooms→ true = true;113 return this;114}this.size ← large, this.crust ← thin, this.cheese ← true, this.pepperoni ← true
pass 1 of 375// Private constructor - use builder //?privateconstructor76private Pizza(Builder builder⟨Pizza$Builder A⟩) {77 this.size→ large = builder.sizelarge;78 this.crust→ thin = builder.crustthin;79 this.cheese→ true = builder.cheesetrue;80 this.pepperoni→ true = builder.pepperonitrue;81 this.mushrooms→ true = builder.mushroomstrue;82 this.onions→ false = builder.onionsfalse;83}All 3 passes — pass 1 is the card above pass builderbuilder.sizebuilder.crustbuilder.cheesebuilder.pepperonibuilder.mushroomsbuilder.onionsthis.sizethis.crustthis.cheesethis.pepperonithis.mushroomsthis.onions1 ⟨Pizza$Builder A⟩ large thin true true true false large thin true true true false 2 ⟨Pizza$Builder B⟩ medium regular false true false true medium regular false true false true 3 ⟨Pizza$Builder C⟩ small regular true false false false small regular true false false false pizza1 ← large pizza, thin crust, cheese, pepperoni, mushrooms
163// Use builder to create Pizza //?usebuilder164Pizza pizza1→ large pizza, thin crust, cheese, pepperoni, mushrooms = new Pizza.Builder("large") //?fluent165 .crust("thin")166 .pepperoni()167 .mushrooms()168 .build();169System.out.println("Pizza 1: " + pizza1large pizza, thin crust, cheese, pepperoni, mushrooms);170171Pizza pizza2 = new Pizza.Builder("medium")172 .pepperoni()173 .onions()174 .noCheese()175 .build();176System.out.println("Pizza 2: " + pizza2);outputPizza 1: large pizza, thin crust, cheese, pepperoni, mushroomsthis.pepperoni ← true
pass 2 of 2106public Builder pepperoni() { //?toppingmethod107 this.pepperoni→ true = true;108 return this;109}this.onions ← true
116public Builder onions() {117 this.onions→ true = true;118 return this;119}this.cheese ← false
121public Builder noCheese() {122 this.cheese→ false = false;123 return this;124}pizza2 ← medium pizza, regular crust, pepperoni, onions
171Pizza pizza2→ medium pizza, regular crust, pepperoni, onions = new Pizza.Builder("medium")172 .pepperoni()173 .onions()174 .noCheese()175 .build();176System.out.println("Pizza 2: " + pizza2medium pizza, regular crust, pepperoni, onions);177178Pizza pizza3 = new Pizza.Builder("small").build(); // Minimal179System.out.println("Pizza 3: " + pizza3);outputPizza 2: medium pizza, regular crust, pepperoni, onionspizza3 ← small pizza, regular crust, cheese
178 Pizza pizza3→ small pizza, regular crust, cheese = new Pizza.Builder("small").build(); // Minimal179 System.out.println("Pizza 3: " + pizza3small pizza, regular crust, cheese);180 181 System.out.println("\n=== Static vs Member Inner Class ===");182 System.out.println("""183 Static Nested Class:184 - Declared with 'static' keyword185 - Can only access outer's static members186 - Does NOT need outer instance187 - Create via: new Outer.Nested()188 - Like a top-level class, just namespaced189 190 Member Inner Class:191 - No 'static' keyword192 - Can access ALL outer members193 - REQUIRES outer instance194 - Create via: outer.new Inner()195 196 When to use static nested:197 - Builder pattern198 - Helper classes that don't need outer state199 - Grouping related classes200 - Entry types for collections201 """);202}outputPizza 3: small pizza, regular crust, cheese === Static vs Member Inner Class === Static Nested Class: - Declared with 'static' keyword - Can only access outer's static members - Does NOT need outer instance - Create via: new Outer.Nested() - Like a top-level class, just namespaced Member Inner Class: - No 'static' keyword - Can access ALL outer members - REQUIRES outer instance - Create via: outer.new Inner() When to use static nested: - Builder pattern - Helper classes that don't need outer state - Grouping related classes - Entry types for collections
static class can only access outer's static members. No outer reference.
Local class
A class defined inside a method.
// Local Class (Class Inside Method)
import java.util.ArrayList;
import java.util.List;
class DataProcessor {
private String processorName;
DataProcessor(String name) {
this.processorName = name;
}
// Method with local class
public List<String> processData(List<String> data, String prefix) {
// Local class defined inside method
class DataTransformer {
private int count = 0;
// Can access method parameters (effectively final)
String transform(String item) {
count++;
// 'prefix' is effectively final - can use it
return prefix + ": " + item.toUpperCase() + " (#" + count + ")";
}
// Can access outer class members
String getProcessorInfo() {
return "Processor: " + processorName;
}
int getCount() {
return count;
}
}
// Use local class
DataTransformer transformer = new DataTransformer();
System.out.println(transformer.getProcessorInfo());
List<String> result = new ArrayList<>();
for (String item : data) {
result.add(transformer.transform(item));
}
System.out.println("Transformed " + transformer.getCount() + " items");
return result;
// DataTransformer not accessible outside this method!
}
// Another example: validator in method
public boolean validateAll(List<Integer> numbers, int minValue, int maxValue) {
// Local class for validation
class RangeValidator {
// Can access minValue, maxValue (effectively final)
boolean isValid(int num) {
return num >= minValue && num <= maxValue;
}
String getRange() {
return "[" + minValue + ", " + maxValue + "]";
}
}
RangeValidator validator = new RangeValidator();
System.out.println("Validating range: " + validator.getRange());
for (int num : numbers) {
if (!validator.isValid(num)) {
System.out.println("Invalid: " + num);
return false;
}
}
return true;
}
}
// Local class implementing interface
class EventSimulator {
interface EventHandler {
void handle(String event);
}
public void simulateEvents(List<String> events) {
// Local class implementing interface
class LoggingHandler implements EventHandler {
private int eventCount = 0;
@Override
public void handle(String event) {
eventCount++;
System.out.println("[Event " + eventCount + "] " + event);
}
public int getEventCount() {
return eventCount;
}
}
LoggingHandler handler = new LoggingHandler();
for (String event : events) {
handler.handle(event);
}
System.out.println("Total events handled: " + handler.getEventCount());
}
}
public class LocalClass {
public static void main(String[] args) {
System.out.println("=== Local Classes ===\n");
System.out.println("--- Data Processing ---");
DataProcessor processor = new DataProcessor("MainProcessor");
List<String> data = List.of("apple", "banana", "cherry");
List<String> processed = processor.processData(data, "ITEM");
System.out.println("\nProcessed data:");
for (String item : processed) {
System.out.println(" " + item);
}
System.out.println("\n--- Validation ---");
List<Integer> numbers = List.of(5, 10, 15, 20, 25);
int maxAllowed = 30;
boolean valid = processor.validateAll(numbers, 1, maxAllowed);
System.out.println("All valid: " + valid);
List<Integer> badNumbers = List.of(5, 10, 50, 20); // 50 is out of range
valid = processor.validateAll(badNumbers, 1, maxAllowed);
System.out.println("All valid: " + valid);
System.out.println("\n--- Event Simulation ---");
EventSimulator simulator = new EventSimulator();
simulator.simulateEvents(List.of("START", "PROCESS", "COMPLETE"));
System.out.println("\n=== Local Class Rules ===");
System.out.println("""
1. Defined inside a method, constructor, or block
2. Scope limited to that block
3. Can access:
- Outer class members (all)
- Local variables that are effectively final
4. Cannot be static
5. Cannot have static members (except constants)
Effectively Final:
- Variable not modified after initialization
- Can use without 'final' keyword (Java 8+)
When to use:
- Helper class needed only in one method
- Encapsulate method-specific logic
- Alternative to anonymous class (when need name/multiple methods)
""");
}
}
// Local Class (Class Inside Method)
import java.util.ArrayList;
import java.util.List;
class DataProcessor {
private String processorName;
DataProcessor(String name) {
this.processorName = name;
}
// Method with local class
public List<String> processData(List<String> data, String prefix) {
// Local class defined inside method
class DataTransformer {
private int count = 0;
// Can access method parameters (effectively final)
String transform(String item) {
count++;
// 'prefix' is effectively final - can use it
return prefix + ": " + item.toUpperCase() + " (#" + count + ")";
}
// Can access outer class members
String getProcessorInfo() {
return "Processor: " + processorName;
}
int getCount() {
return count;
}
}
// Use local class
DataTransformer transformer = new DataTransformer();
System.out.println(transformer.getProcessorInfo());
List<String> result = new ArrayList<>();
for (String item : data) {
result.add(transformer.transform(item));
}
System.out.println("Transformed " + transformer.getCount() + " items");
return result;
// DataTransformer not accessible outside this method!
}
// Another example: validator in method
public boolean validateAll(List<Integer> numbers, int minValue, int maxValue) {
// Local class for validation
class RangeValidator {
// Can access minValue, maxValue (effectively final)
boolean isValid(int num) {
return num >= minValue && num <= maxValue;
}
String getRange() {
return "[" + minValue + ", " + maxValue + "]";
}
}
RangeValidator validator = new RangeValidator();
System.out.println("Validating range: " + validator.getRange());
for (int num : numbers) {
if (!validator.isValid(num)) {
System.out.println("Invalid: " + num);
return false;
}
}
return true;
}
}
// Local class implementing interface
class EventSimulator {
interface EventHandler {
void handle(String event);
}
public void simulateEvents(List<String> events) {
// Local class implementing interface
class LoggingHandler implements EventHandler {
private int eventCount = 0;
@Override
public void handle(String event) {
eventCount++;
System.out.println("[Event " + eventCount + "] " + event);
}
public int getEventCount() {
return eventCount;
}
}
LoggingHandler handler = new LoggingHandler();
for (String event : events) {
handler.handle(event);
}
System.out.println("Total events handled: " + handler.getEventCount());
}
}
public class LocalClass {
public static void main(String[] args) {
System.out.println("=== Local Classes ===\n");
System.out.println("--- Data Processing ---");
DataProcessor processor = new DataProcessor("MainProcessor");
List<String> data = List.of("apple", "banana", "cherry");
List<String> processed = processor.processData(data, "ITEM");
System.out.println("\nProcessed data:");
for (String item : processed) {
System.out.println(" " + item);
}
System.out.println("\n--- Validation ---");
List<Integer> numbers = List.of(5, 10, 15, 20, 25);
int maxAllowed = 18;
boolean valid = processor.validateAll(numbers, 1, maxAllowed);
System.out.println("All valid: " + valid);
List<Integer> badNumbers = List.of(5, 10, 50, 20); // 50 is out of range
valid = processor.validateAll(badNumbers, 1, maxAllowed);
System.out.println("All valid: " + valid);
System.out.println("\n--- Event Simulation ---");
EventSimulator simulator = new EventSimulator();
simulator.simulateEvents(List.of("START", "PROCESS", "COMPLETE"));
System.out.println("\n=== Local Class Rules ===");
System.out.println("""
1. Defined inside a method, constructor, or block
2. Scope limited to that block
3. Can access:
- Outer class members (all)
- Local variables that are effectively final
4. Cannot be static
5. Cannot have static members (except constants)
Effectively Final:
- Variable not modified after initialization
- Can use without 'final' keyword (Java 8+)
When to use:
- Helper class needed only in one method
- Encapsulate method-specific logic
- Alternative to anonymous class (when need name/multiple methods)
""");
}
}
public static void main(String[] args)
113public class LocalClass {114 public static void main(String[] args) {115 System.out.println("=== Local Classes ===\n");116 117 System.out.println("--- Data Processing ---");118 DataProcessor processor = new DataProcessor("MainProcessor");output=== Local Classes === --- Data Processing ---this.processorName ← MainProcessor
9DataProcessor(String nameMainProcessor) {10 this.processorName→ MainProcessor = nameMainProcessor;11}processor ← ⟨DataProcessor A⟩, data ← [apple, banana, cherry]
117System.out.println("--- Data Processing ---");118DataProcessor processor→ ⟨DataProcessor A⟩ = new DataProcessor("MainProcessor");119120List<String> data→ [apple, banana, cherry] = List.of("apple", "banana", "cherry");121List<String> processed = processor.processData(data[apple, banana, cherry], "ITEM");public List<String> processData(List<String> data, String prefix)
13// Method with local class //?methodwithlocal14public List<String> processData(List<String> data[apple, banana, cherry], String prefixITEM) { //?processmethod15 16 // Local class defined inside method //?localclass17 class DataTransformer { //?localdefinition18 private int count = 0;19 20 // Can access method parameters (effectively final) //?accessparams21 String transform(String item) {22 count++;23 // 'prefix' is effectively final - can use it //?effectivelyfinal24 return prefix + ": " + item.toUpperCase() + " (#" + count + ")";25 }26 27 // Can access outer class members //?accessouter28 String getProcessorInfo() {29 return "Processor: " + processorName;30 }31 32 int getCount() {33 return count;34 }35 }36 37 // Use local class //?uselocal38 DataTransformer transformer = new DataTransformer();39 System.out.println(transformer.getProcessorInfo());String getProcessorInfo()
27// Can access outer class members //?accessouter28String getProcessorInfo() {29 return "Processor: " + processorNameMainProcessor;30}result ← []
38DataTransformer transformer = new DataTransformer();39System.out.println(transformer.getProcessorInfo());4041List<String> result→ [] = new ArrayList<>();42for (String item : data) {outputProcessor: MainProcessorfor (String item : data)
pass 1 of 341List<String> result = new ArrayList<>();42for (String itemapple : data[apple, banana, cherry]) {43 result.add(transformer.transform(itemapple));44}All 3 passes — pass 1 is the card above pass item1 apple 2 banana 3 cherry count ← 1
pass 1 of 320// Can access method parameters (effectively final) //?accessparams21String transform(String itemapple) {22 count→ 1++;23 // 'prefix' is effectively final - can use it //?effectivelyfinal24 return prefixITEM + ": " + item.toUpperCase() + " (#" + count1 + ")";25}All 3 passes — pass 1 is the card above pass itemcount1 apple 0 → 1 2 banana 1 → 2 3 cherry 2 → 3 result.add(transformer.transform(item));
42for (String item : data) {43 result.add(transformer.transform(itemapple));44}result.add(transformer.transform(item));
42for (String item : data) {43 result.add(transformer.transform(itembanana));44}result.add(transformer.transform(item));
42for (String item : data) {43 result.add(transformer.transform(itemcherry));44}System.out.println("Transformed " + transformer.getCount() + " items")…
46System.out.println("Transformed " + transformer.getCount() + " items");47return result;int getCount()
32int getCount() {33 return count3;34}return result;
46System.out.println("Transformed " + transformer.getCount() + " items");47return result[ITEM: APPLE (#1), ITEM: BANANA (#2), ITEM: CHERRY (#3)];outputTransformed 3 itemsprocessed ← [ITEM: APPLE (#1), ITEM: BANANA (#2), ITEM: CHERRY (#3)]
120List<String> data = List.of("apple", "banana", "cherry");121List<String> processed→ [ITEM: APPLE (#1), ITEM: BANANA (#2), ITEM: CHERRY (#3)] = processor.processData(data[apple, banana, cherry], "ITEM");122123System.out.println("\nProcessed data:");124for (String item : processed) {output Processed data:for (String item : processed)
pass 1 of 3123System.out.println("\nProcessed data:");124for (String itemITEM: APPLE (#1) : processed[ITEM: APPLE (#1), ITEM: BANANA (#2), ITEM: CHERRY (#3)]) {125 System.out.println(" " + itemITEM: APPLE (#1));126}output ITEM: APPLE (#1)All 3 passes — pass 1 is the card above pass item1 ITEM: APPLE (#1) 2 ITEM: BANANA (#2) 3 ITEM: CHERRY (#3) numbers ← [5, 10, 15, 20, 25], maxAllowed ← 30
128System.out.println("\n--- Validation ---");129List<Integer> numbers→ [5, 10, 15, 20, 25] = List.of(5, 10, 15, 20, 25);130int maxAllowed→ 30 = 30; //@maxAllowed=30, 18131boolean valid = processor.validateAll(numbers[5, 10, 15, 20, 25], 1, maxAllowed30);132System.out.println("All valid: " + valid);output --- Validation ---public boolean validateAll(List<Integer> numbers, int minValue, int ma…
pass 1 of 252// Another example: validator in method //?validatorexample53public boolean validateAll(List<Integer> numbers[5, 10, 15, 20, 25], int minValue1, int maxValue30) {54 55 // Local class for validation //?localvalidator56 class RangeValidator {57 // Can access minValue, maxValue (effectively final)58 boolean isValid(int num) {59 return num >= minValue && num <= maxValue; //?accessminmax60 }61 62 String getRange() {63 return "[" + minValue + ", " + maxValue + "]";64 }65 }66 67 RangeValidator validator = new RangeValidator();68 System.out.println("Validating range: " + validator.getRange());String getRange()
pass 1 of 262String getRange() {63 return "[" + minValue1 + ", " + maxValue30 + "]";64}System.out.println("Validating range: " + validator.getRange());
67RangeValidator validator = new RangeValidator();68System.out.println("Validating range: " + validator.getRange());outputValidating range: [1, 30]for (int num : numbers)
pass 1 of 870for (int num5 : numbers[5, 10, 15, 20, 25]) {71 if (!validator.isValid(num)) {All 8 passes — pass 1 is the card above pass numnumbers1 5 [5, 10, 15, 20, 25] 2 10 [5, 10, 15, 20, 25] 3 15 [5, 10, 15, 20, 25] 4 20 [5, 10, 15, 20, 25] 5 25 [5, 10, 15, 20, 25] 6 5 [5, 10, 50, 20] 7 10 [5, 10, 50, 20] 8 50 [5, 10, 50, 20] boolean isValid(int num)
pass 1 of 857// Can access minValue, maxValue (effectively final)58boolean isValid(int num5) {59 return num5 >= minValue1 && num <= maxValue30; //?accessminmax60}All 8 passes — pass 1 is the card above pass num1 5 2 10 3 15 4 20 5 25 6 5 7 10 8 50 return true;
75 }76 return true;77}valid ← true, badNumbers ← [5, 10, 50, 20]
130int maxAllowed = 30; //@maxAllowed=30, 18131boolean valid→ true = processor.validateAll(numbers[5, 10, 15, 20, 25], 1, maxAllowed30);132System.out.println("All valid: " + validtrue);133134List<Integer> badNumbers→ [5, 10, 50, 20] = List.of(5, 10, 50, 20); // 50 is out of range135valid = processor.validateAll(badNumbers[5, 10, 50, 20], 1, maxAllowed30);136System.out.println("All valid: " + valid);outputAll valid: truepublic boolean validateAll(List<Integer> numbers, int minValue, int ma…
pass 2 of 252// Another example: validator in method //?validatorexample53public boolean validateAll(List<Integer> numbers[5, 10, 50, 20], int minValue1, int maxValue30) {54 55 // Local class for validation //?localvalidator56 class RangeValidator {57 // Can access minValue, maxValue (effectively final)58 boolean isValid(int num) {59 return num >= minValue && num <= maxValue; //?accessminmax60 }61 62 String getRange() {63 return "[" + minValue + ", " + maxValue + "]";64 }65 }66 67 RangeValidator validator = new RangeValidator();68 System.out.println("Validating range: " + validator.getRange());String getRange()
pass 2 of 262String getRange() {63 return "[" + minValue1 + ", " + maxValue30 + "]";64}System.out.println("Validating range: " + validator.getRange());
67RangeValidator validator = new RangeValidator();68System.out.println("Validating range: " + validator.getRange());outputValidating range: [1, 30]if (!validator.isValid(num))
70for (int num : numbers) {71 if (!validator.isValid(num50)) {72 System.out.println("Invalid: " + num50);73 return false;74 }outputInvalid: 50valid ← false, simulator ← ⟨EventSimulator B⟩
134List<Integer> badNumbers = List.of(5, 10, 50, 20); // 50 is out of range135valid→ false = processor.validateAll(badNumbers[5, 10, 50, 20], 1, maxAllowed30);136System.out.println("All valid: " + validfalse);137138System.out.println("\n--- Event Simulation ---");139EventSimulator simulator→ ⟨EventSimulator B⟩ = new EventSimulator();140simulator.simulateEvents(List.of("START", "PROCESS", "COMPLETE"));outputAll valid: false --- Event Simulation ---public void simulateEvents(List<String> events)
87public void simulateEvents(List<String> events[START, PROCESS, COMPLETE]) {88 // Local class implementing interface //?localimplfor (String event : events)
pass 1 of 3105for (String eventSTART : events[START, PROCESS, COMPLETE]) {106 handler.handle(eventSTART);107}All 3 passes — pass 1 is the card above pass event1 START 2 PROCESS 3 COMPLETE eventCount ← 1
pass 1 of 392@Override93public void handle(String eventSTART) {94 eventCount→ 1++;95 System.out.println("[Event " + eventCount1 + "] " + eventSTART);96}output[Event 1] STARTAll 3 passes — pass 1 is the card above pass eventeventCount1 START 0 → 1 2 PROCESS 1 → 2 3 COMPLETE 2 → 3 handler.handle(event);
105for (String event : events) {106 handler.handle(eventSTART);107}handler.handle(event);
105for (String event : events) {106 handler.handle(eventPROCESS);107}handler.handle(event);
105for (String event : events) {106 handler.handle(eventCOMPLETE);107}System.out.println("Total events handled: " + handler.getEventCount())…
109 System.out.println("Total events handled: " + handler.getEventCount());110}public int getEventCount()
98public int getEventCount() {99 return eventCount3;100}System.out.println("Total events handled: " + handler.getEventCount())…
109 System.out.println("Total events handled: " + handler.getEventCount());110}outputTotal events handled: 3simulator.simulateEvents(List.of("START", "PROCESS", "COMPLETE"));
139 EventSimulator simulator = new EventSimulator();140 simulator.simulateEvents(List.of("START", "PROCESS", "COMPLETE"));141 142 System.out.println("\n=== Local Class Rules ===");143 System.out.println("""144 1. Defined inside a method, constructor, or block145 2. Scope limited to that block146 3. Can access:147 - Outer class members (all)148 - Local variables that are effectively final149 4. Cannot be static150 5. Cannot have static members (except constants)151 152 Effectively Final:153 - Variable not modified after initialization154 - Can use without 'final' keyword (Java 8+)155 156 When to use:157 - Helper class needed only in one method158 - Encapsulate method-specific logic159 - Alternative to anonymous class (when need name/multiple methods)160 """);161}output === Local Class Rules === 1. Defined inside a method, constructor, or block 2. Scope limited to that block 3. Can access: - Outer class members (all) - Local variables that are effectively final 4. Cannot be static 5. Cannot have static members (except constants) Effectively Final: - Variable not modified after initialization - Can use without 'final' keyword (Java 8+) When to use: - Helper class needed only in one method - Encapsulate method-specific logic - Alternative to anonymous class (when need name/multiple methods)
public static void main(String[] args)
113public class LocalClass {114 public static void main(String[] args) {115 System.out.println("=== Local Classes ===\n");116 117 System.out.println("--- Data Processing ---");118 DataProcessor processor = new DataProcessor("MainProcessor");output=== Local Classes === --- Data Processing ---this.processorName ← MainProcessor
9DataProcessor(String nameMainProcessor) {10 this.processorName→ MainProcessor = nameMainProcessor;11}processor ← ⟨DataProcessor A⟩, data ← [apple, banana, cherry]
117System.out.println("--- Data Processing ---");118DataProcessor processor→ ⟨DataProcessor A⟩ = new DataProcessor("MainProcessor");119120List<String> data→ [apple, banana, cherry] = List.of("apple", "banana", "cherry");121List<String> processed = processor.processData(data[apple, banana, cherry], "ITEM");public List<String> processData(List<String> data, String prefix)
13// Method with local class14public List<String> processData(List<String> data[apple, banana, cherry], String prefixITEM) {15 16 // Local class defined inside method17 class DataTransformer {18 private int count = 0;19 20 // Can access method parameters (effectively final)21 String transform(String item) {22 count++;23 // 'prefix' is effectively final - can use it24 return prefix + ": " + item.toUpperCase() + " (#" + count + ")";25 }26 27 // Can access outer class members28 String getProcessorInfo() {29 return "Processor: " + processorName;30 }31 32 int getCount() {33 return count;34 }35 }36 37 // Use local class38 DataTransformer transformer = new DataTransformer();39 System.out.println(transformer.getProcessorInfo());String getProcessorInfo()
27// Can access outer class members28String getProcessorInfo() {29 return "Processor: " + processorNameMainProcessor;30}result ← []
38DataTransformer transformer = new DataTransformer();39System.out.println(transformer.getProcessorInfo());4041List<String> result→ [] = new ArrayList<>();42for (String item : data) {outputProcessor: MainProcessorfor (String item : data)
pass 1 of 341List<String> result = new ArrayList<>();42for (String itemapple : data[apple, banana, cherry]) {43 result.add(transformer.transform(itemapple));44}All 3 passes — pass 1 is the card above pass item1 apple 2 banana 3 cherry count ← 1
pass 1 of 320// Can access method parameters (effectively final)21String transform(String itemapple) {22 count→ 1++;23 // 'prefix' is effectively final - can use it24 return prefixITEM + ": " + item.toUpperCase() + " (#" + count1 + ")";25}All 3 passes — pass 1 is the card above pass itemcount1 apple 0 → 1 2 banana 1 → 2 3 cherry 2 → 3 result.add(transformer.transform(item));
42for (String item : data) {43 result.add(transformer.transform(itemapple));44}result.add(transformer.transform(item));
42for (String item : data) {43 result.add(transformer.transform(itembanana));44}result.add(transformer.transform(item));
42for (String item : data) {43 result.add(transformer.transform(itemcherry));44}System.out.println("Transformed " + transformer.getCount() + " items")…
46System.out.println("Transformed " + transformer.getCount() + " items");47return result;int getCount()
32int getCount() {33 return count3;34}return result;
46System.out.println("Transformed " + transformer.getCount() + " items");47return result[ITEM: APPLE (#1), ITEM: BANANA (#2), ITEM: CHERRY (#3)];outputTransformed 3 itemsprocessed ← [ITEM: APPLE (#1), ITEM: BANANA (#2), ITEM: CHERRY (#3)]
120List<String> data = List.of("apple", "banana", "cherry");121List<String> processed→ [ITEM: APPLE (#1), ITEM: BANANA (#2), ITEM: CHERRY (#3)] = processor.processData(data[apple, banana, cherry], "ITEM");122123System.out.println("\nProcessed data:");124for (String item : processed) {output Processed data:for (String item : processed)
pass 1 of 3123System.out.println("\nProcessed data:");124for (String itemITEM: APPLE (#1) : processed[ITEM: APPLE (#1), ITEM: BANANA (#2), ITEM: CHERRY (#3)]) {125 System.out.println(" " + itemITEM: APPLE (#1));126}output ITEM: APPLE (#1)All 3 passes — pass 1 is the card above pass item1 ITEM: APPLE (#1) 2 ITEM: BANANA (#2) 3 ITEM: CHERRY (#3) numbers ← [5, 10, 15, 20, 25], maxAllowed ← 18
128System.out.println("\n--- Validation ---");129List<Integer> numbers→ [5, 10, 15, 20, 25] = List.of(5, 10, 15, 20, 25);130int maxAllowed→ 18 = 18;131boolean valid = processor.validateAll(numbers[5, 10, 15, 20, 25], 1, maxAllowed18);132System.out.println("All valid: " + valid);output --- Validation ---public boolean validateAll(List<Integer> numbers, int minValue, int ma…
pass 1 of 252// Another example: validator in method53public boolean validateAll(List<Integer> numbers[5, 10, 15, 20, 25], int minValue1, int maxValue18) {54 55 // Local class for validation56 class RangeValidator {57 // Can access minValue, maxValue (effectively final)58 boolean isValid(int num) {59 return num >= minValue && num <= maxValue;60 }61 62 String getRange() {63 return "[" + minValue + ", " + maxValue + "]";64 }65 }66 67 RangeValidator validator = new RangeValidator();68 System.out.println("Validating range: " + validator.getRange());String getRange()
pass 1 of 262String getRange() {63 return "[" + minValue1 + ", " + maxValue18 + "]";64}System.out.println("Validating range: " + validator.getRange());
67RangeValidator validator = new RangeValidator();68System.out.println("Validating range: " + validator.getRange());outputValidating range: [1, 18]for (int num : numbers)
pass 1 of 770for (int num5 : numbers[5, 10, 15, 20, 25]) {71 if (!validator.isValid(num)) {All 7 passes — pass 1 is the card above pass numnumbers1 5 [5, 10, 15, 20, 25] 2 10 [5, 10, 15, 20, 25] 3 15 [5, 10, 15, 20, 25] 4 20 [5, 10, 15, 20, 25] 5 5 [5, 10, 50, 20] 6 10 [5, 10, 50, 20] 7 50 [5, 10, 50, 20] boolean isValid(int num)
pass 1 of 757// Can access minValue, maxValue (effectively final)58boolean isValid(int num5) {59 return num5 >= minValue1 && num <= maxValue18;60}All 7 passes — pass 1 is the card above pass num1 5 2 10 3 15 4 20 5 5 6 10 7 50 if (!validator.isValid(num))
pass 1 of 270for (int num : numbers) {71 if (!validator.isValid(num20)) {72 System.out.println("Invalid: " + num20);73 return false;74 }outputInvalid: 20valid ← false, badNumbers ← [5, 10, 50, 20]
130int maxAllowed = 18;131boolean valid→ false = processor.validateAll(numbers[5, 10, 15, 20, 25], 1, maxAllowed18);132System.out.println("All valid: " + validfalse);133134List<Integer> badNumbers→ [5, 10, 50, 20] = List.of(5, 10, 50, 20); // 50 is out of range135valid = processor.validateAll(badNumbers[5, 10, 50, 20], 1, maxAllowed18);136System.out.println("All valid: " + valid);outputAll valid: falsepublic boolean validateAll(List<Integer> numbers, int minValue, int ma…
pass 2 of 252// Another example: validator in method53public boolean validateAll(List<Integer> numbers[5, 10, 50, 20], int minValue1, int maxValue18) {54 55 // Local class for validation56 class RangeValidator {57 // Can access minValue, maxValue (effectively final)58 boolean isValid(int num) {59 return num >= minValue && num <= maxValue;60 }61 62 String getRange() {63 return "[" + minValue + ", " + maxValue + "]";64 }65 }66 67 RangeValidator validator = new RangeValidator();68 System.out.println("Validating range: " + validator.getRange());String getRange()
pass 2 of 262String getRange() {63 return "[" + minValue1 + ", " + maxValue18 + "]";64}System.out.println("Validating range: " + validator.getRange());
67RangeValidator validator = new RangeValidator();68System.out.println("Validating range: " + validator.getRange());outputValidating range: [1, 18]if (!validator.isValid(num))
pass 2 of 270for (int num : numbers) {71 if (!validator.isValid(num50)) {72 System.out.println("Invalid: " + num50);73 return false;74 }outputInvalid: 50valid ← false, simulator ← ⟨EventSimulator B⟩
134List<Integer> badNumbers = List.of(5, 10, 50, 20); // 50 is out of range135valid→ false = processor.validateAll(badNumbers[5, 10, 50, 20], 1, maxAllowed18);136System.out.println("All valid: " + validfalse);137138System.out.println("\n--- Event Simulation ---");139EventSimulator simulator→ ⟨EventSimulator B⟩ = new EventSimulator();140simulator.simulateEvents(List.of("START", "PROCESS", "COMPLETE"));outputAll valid: false --- Event Simulation ---public void simulateEvents(List<String> events)
87public void simulateEvents(List<String> events[START, PROCESS, COMPLETE]) {88 // Local class implementing interfacefor (String event : events)
pass 1 of 3105for (String eventSTART : events[START, PROCESS, COMPLETE]) {106 handler.handle(eventSTART);107}All 3 passes — pass 1 is the card above pass event1 START 2 PROCESS 3 COMPLETE eventCount ← 1
pass 1 of 392@Override93public void handle(String eventSTART) {94 eventCount→ 1++;95 System.out.println("[Event " + eventCount1 + "] " + eventSTART);96}output[Event 1] STARTAll 3 passes — pass 1 is the card above pass eventeventCount1 START 0 → 1 2 PROCESS 1 → 2 3 COMPLETE 2 → 3 handler.handle(event);
105for (String event : events) {106 handler.handle(eventSTART);107}handler.handle(event);
105for (String event : events) {106 handler.handle(eventPROCESS);107}handler.handle(event);
105for (String event : events) {106 handler.handle(eventCOMPLETE);107}System.out.println("Total events handled: " + handler.getEventCount())…
109 System.out.println("Total events handled: " + handler.getEventCount());110}public int getEventCount()
98public int getEventCount() {99 return eventCount3;100}System.out.println("Total events handled: " + handler.getEventCount())…
109 System.out.println("Total events handled: " + handler.getEventCount());110}outputTotal events handled: 3simulator.simulateEvents(List.of("START", "PROCESS", "COMPLETE"));
139 EventSimulator simulator = new EventSimulator();140 simulator.simulateEvents(List.of("START", "PROCESS", "COMPLETE"));141 142 System.out.println("\n=== Local Class Rules ===");143 System.out.println("""144 1. Defined inside a method, constructor, or block145 2. Scope limited to that block146 3. Can access:147 - Outer class members (all)148 - Local variables that are effectively final149 4. Cannot be static150 5. Cannot have static members (except constants)151 152 Effectively Final:153 - Variable not modified after initialization154 - Can use without 'final' keyword (Java 8+)155 156 When to use:157 - Helper class needed only in one method158 - Encapsulate method-specific logic159 - Alternative to anonymous class (when need name/multiple methods)160 """);161}output === Local Class Rules === 1. Defined inside a method, constructor, or block 2. Scope limited to that block 3. Can access: - Outer class members (all) - Local variables that are effectively final 4. Cannot be static 5. Cannot have static members (except constants) Effectively Final: - Variable not modified after initialization - Can use without 'final' keyword (Java 8+) When to use: - Helper class needed only in one method - Encapsulate method-specific logic - Alternative to anonymous class (when need name/multiple methods)
Local classes exist only within the method. Can access final/effectively final locals.
Anonymous class
One-time class definition and instantiation.
// Anonymous Class
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
interface Greeting {
void greet(String name);
}
abstract class Animal {
abstract void makeSound();
void sleep() {
System.out.println("Zzz...");
}
}
class SortingDemo {
// Using anonymous class for Comparator
public void sortStrings(List<String> strings) {
// Anonymous class implementing Comparator
Comparator<String> lengthComparator = new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return Integer.compare(s1.length(), s2.length());
}
};
Collections.sort(strings, lengthComparator);
}
// Anonymous class inline
public void sortByLastChar(List<String> strings) {
Collections.sort(strings, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
char last1 = s1.charAt(s1.length() - 1);
char last2 = s2.charAt(s2.length() - 1);
return Character.compare(last1, last2);
}
});
}
}
class ButtonSimulator {
interface ClickListener {
void onClick();
}
private ClickListener listener;
public void setOnClickListener(ClickListener listener) {
this.listener = listener;
}
public void click() {
if (listener != null) {
listener.onClick();
}
}
}
public class AnonymousClass {
public static void main(String[] args) {
System.out.println("=== Anonymous Classes ===\n");
// Anonymous class implementing interface
System.out.println("--- Implementing Interface ---");
Greeting formalGreeting = new Greeting() {
@Override
public void greet(String name) {
System.out.println("Good day, " + name + ". How do you do?");
}
};
Greeting casualGreeting = new Greeting() {
@Override
public void greet(String name) {
System.out.println("Hey " + name + "! What's up?");
}
};
formalGreeting.greet("Sir");
casualGreeting.greet("buddy");
// Anonymous class extending abstract class
System.out.println("\n--- Extending Abstract Class ---");
Animal dog = new Animal() {
@Override
void makeSound() {
System.out.println("Woof woof!");
}
};
Animal cat = new Animal() {
@Override
void makeSound() {
System.out.println("Meow!");
}
// Can add new methods, but can't call via Animal reference
void purr() {
System.out.println("Purrrr...");
}
};
dog.makeSound();
dog.sleep(); // Inherited method
cat.makeSound();
// cat.purr(); // Cannot call - Animal doesn't have purr()
// Sorting with anonymous Comparator
System.out.println("\n--- Sorting with Anonymous Comparator ---");
List<String> words = new ArrayList<>(List.of("cat", "elephant", "dog", "butterfly"));
System.out.println("Original: " + words);
SortingDemo sorter = new SortingDemo();
sorter.sortStrings(words);
System.out.println("By length: " + words);
words = new ArrayList<>(List.of("cat", "elephant", "dog", "butterfly"));
sorter.sortByLastChar(words);
System.out.println("By last char: " + words);
// Event listener pattern
System.out.println("\n--- Event Listener Pattern ---");
ButtonSimulator button = new ButtonSimulator();
button.setOnClickListener(new ButtonSimulator.ClickListener() {
private int clickCount = 0; // Anonymous class can have state!
@Override
public void onClick() {
clickCount++;
System.out.println("Button clicked! Count: " + clickCount);
}
});
button.click();
button.click();
button.click();
// Capturing local variables
System.out.println("\n--- Capturing Local Variables ---");
String message = "Hello"; // Effectively final
int times = 3;
Runnable printer = new Runnable() {
@Override
public void run() {
for (int i = 0; i < times; i++) {
System.out.println(message);
}
}
};
printer.run();
// message = "Changed"; // Would cause error - breaks effectively final
System.out.println("\n=== Anonymous Class Rules ===");
System.out.println("""
1. No name - defined and instantiated in one expression
2. Implements interface OR extends class (not both)
3. Must end with semicolon after closing brace
4. Cannot have explicit constructor
5. Can have instance fields and methods
6. Can capture effectively final local variables
Syntax:
new Interface() { ... };
new ClassName(args) { ... };
When to use:
- One-time implementation needed
- Simple interface (1-2 methods)
- Event listeners/callbacks
Modern alternative: Lambda expressions (for single-method interfaces)
""");
}
}
// Anonymous Class
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
interface Greeting {
void greet(String name);
}
abstract class Animal {
abstract void makeSound();
void sleep() {
System.out.println("Zzz...");
}
}
class SortingDemo {
// Using anonymous class for Comparator
public void sortStrings(List<String> strings) {
// Anonymous class implementing Comparator
Comparator<String> lengthComparator = new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return Integer.compare(s1.length(), s2.length());
}
};
Collections.sort(strings, lengthComparator);
}
// Anonymous class inline
public void sortByLastChar(List<String> strings) {
Collections.sort(strings, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
char last1 = s1.charAt(s1.length() - 1);
char last2 = s2.charAt(s2.length() - 1);
return Character.compare(last1, last2);
}
});
}
}
class ButtonSimulator {
interface ClickListener {
void onClick();
}
private ClickListener listener;
public void setOnClickListener(ClickListener listener) {
this.listener = listener;
}
public void click() {
if (listener != null) {
listener.onClick();
}
}
}
public class AnonymousClass {
public static void main(String[] args) {
System.out.println("=== Anonymous Classes ===\n");
// Anonymous class implementing interface
System.out.println("--- Implementing Interface ---");
Greeting formalGreeting = new Greeting() {
@Override
public void greet(String name) {
System.out.println("Good day, " + name + ". How do you do?");
}
};
Greeting casualGreeting = new Greeting() {
@Override
public void greet(String name) {
System.out.println("Hey " + name + "! What's up?");
}
};
formalGreeting.greet("Sir");
casualGreeting.greet("buddy");
// Anonymous class extending abstract class
System.out.println("\n--- Extending Abstract Class ---");
Animal dog = new Animal() {
@Override
void makeSound() {
System.out.println("Woof woof!");
}
};
Animal cat = new Animal() {
@Override
void makeSound() {
System.out.println("Meow!");
}
// Can add new methods, but can't call via Animal reference
void purr() {
System.out.println("Purrrr...");
}
};
dog.makeSound();
dog.sleep(); // Inherited method
cat.makeSound();
// cat.purr(); // Cannot call - Animal doesn't have purr()
// Sorting with anonymous Comparator
System.out.println("\n--- Sorting with Anonymous Comparator ---");
List<String> words = new ArrayList<>(List.of("cat", "elephant", "dog", "butterfly"));
System.out.println("Original: " + words);
SortingDemo sorter = new SortingDemo();
sorter.sortStrings(words);
System.out.println("By length: " + words);
words = new ArrayList<>(List.of("cat", "elephant", "dog", "butterfly"));
sorter.sortByLastChar(words);
System.out.println("By last char: " + words);
// Event listener pattern
System.out.println("\n--- Event Listener Pattern ---");
ButtonSimulator button = new ButtonSimulator();
button.setOnClickListener(new ButtonSimulator.ClickListener() {
private int clickCount = 0; // Anonymous class can have state!
@Override
public void onClick() {
clickCount++;
System.out.println("Button clicked! Count: " + clickCount);
}
});
button.click();
button.click();
button.click();
// Capturing local variables
System.out.println("\n--- Capturing Local Variables ---");
String message = "Hello"; // Effectively final
int times = 1;
Runnable printer = new Runnable() {
@Override
public void run() {
for (int i = 0; i < times; i++) {
System.out.println(message);
}
}
};
printer.run();
// message = "Changed"; // Would cause error - breaks effectively final
System.out.println("\n=== Anonymous Class Rules ===");
System.out.println("""
1. No name - defined and instantiated in one expression
2. Implements interface OR extends class (not both)
3. Must end with semicolon after closing brace
4. Cannot have explicit constructor
5. Can have instance fields and methods
6. Can capture effectively final local variables
Syntax:
new Interface() { ... };
new ClassName(args) { ... };
When to use:
- One-time implementation needed
- Simple interface (1-2 methods)
- Event listeners/callbacks
Modern alternative: Lambda expressions (for single-method interfaces)
""");
}
}
// Anonymous Class
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
interface Greeting {
void greet(String name);
}
abstract class Animal {
abstract void makeSound();
void sleep() {
System.out.println("Zzz...");
}
}
class SortingDemo {
// Using anonymous class for Comparator
public void sortStrings(List<String> strings) {
// Anonymous class implementing Comparator
Comparator<String> lengthComparator = new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return Integer.compare(s1.length(), s2.length());
}
};
Collections.sort(strings, lengthComparator);
}
// Anonymous class inline
public void sortByLastChar(List<String> strings) {
Collections.sort(strings, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
char last1 = s1.charAt(s1.length() - 1);
char last2 = s2.charAt(s2.length() - 1);
return Character.compare(last1, last2);
}
});
}
}
class ButtonSimulator {
interface ClickListener {
void onClick();
}
private ClickListener listener;
public void setOnClickListener(ClickListener listener) {
this.listener = listener;
}
public void click() {
if (listener != null) {
listener.onClick();
}
}
}
public class AnonymousClass {
public static void main(String[] args) {
System.out.println("=== Anonymous Classes ===\n");
// Anonymous class implementing interface
System.out.println("--- Implementing Interface ---");
Greeting formalGreeting = new Greeting() {
@Override
public void greet(String name) {
System.out.println("Good day, " + name + ". How do you do?");
}
};
Greeting casualGreeting = new Greeting() {
@Override
public void greet(String name) {
System.out.println("Hey " + name + "! What's up?");
}
};
formalGreeting.greet("Sir");
casualGreeting.greet("buddy");
// Anonymous class extending abstract class
System.out.println("\n--- Extending Abstract Class ---");
Animal dog = new Animal() {
@Override
void makeSound() {
System.out.println("Woof woof!");
}
};
Animal cat = new Animal() {
@Override
void makeSound() {
System.out.println("Meow!");
}
// Can add new methods, but can't call via Animal reference
void purr() {
System.out.println("Purrrr...");
}
};
dog.makeSound();
dog.sleep(); // Inherited method
cat.makeSound();
// cat.purr(); // Cannot call - Animal doesn't have purr()
// Sorting with anonymous Comparator
System.out.println("\n--- Sorting with Anonymous Comparator ---");
List<String> words = new ArrayList<>(List.of("cat", "elephant", "dog", "butterfly"));
System.out.println("Original: " + words);
SortingDemo sorter = new SortingDemo();
sorter.sortStrings(words);
System.out.println("By length: " + words);
words = new ArrayList<>(List.of("cat", "elephant", "dog", "butterfly"));
sorter.sortByLastChar(words);
System.out.println("By last char: " + words);
// Event listener pattern
System.out.println("\n--- Event Listener Pattern ---");
ButtonSimulator button = new ButtonSimulator();
button.setOnClickListener(new ButtonSimulator.ClickListener() {
private int clickCount = 0; // Anonymous class can have state!
@Override
public void onClick() {
clickCount++;
System.out.println("Button clicked! Count: " + clickCount);
}
});
button.click();
button.click();
button.click();
// Capturing local variables
System.out.println("\n--- Capturing Local Variables ---");
String message = "Hello"; // Effectively final
int times = 5;
Runnable printer = new Runnable() {
@Override
public void run() {
for (int i = 0; i < times; i++) {
System.out.println(message);
}
}
};
printer.run();
// message = "Changed"; // Would cause error - breaks effectively final
System.out.println("\n=== Anonymous Class Rules ===");
System.out.println("""
1. No name - defined and instantiated in one expression
2. Implements interface OR extends class (not both)
3. Must end with semicolon after closing brace
4. Cannot have explicit constructor
5. Can have instance fields and methods
6. Can capture effectively final local variables
Syntax:
new Interface() { ... };
new ClassName(args) { ... };
When to use:
- One-time implementation needed
- Simple interface (1-2 methods)
- Event listeners/callbacks
Modern alternative: Lambda expressions (for single-method interfaces)
""");
}
}
formalGreeting ← ⟨AnonymousClass$1 A⟩, casualGreeting ← ⟨AnonymousClass$2 B⟩
66public class AnonymousClass {67 public static void main(String[] args) {68 System.out.println("=== Anonymous Classes ===\n");69 70 // Anonymous class implementing interface //?anoninterface71 System.out.println("--- Implementing Interface ---");72 Greeting formalGreeting→ ⟨AnonymousClass$1 A⟩ = new Greeting() { //?formalgreeting73 @Override74 public void greet(String name) {75 System.out.println("Good day, " + name + ". How do you do?");76 }77 };78 79 Greeting casualGreeting→ ⟨AnonymousClass$2 B⟩ = new Greeting() { //?casualgreeting80 @Override81 public void greet(String name) {82 System.out.println("Hey " + name + "! What's up?");83 }84 };85 86 formalGreeting.greet("Sir");87 casualGreeting.greet("buddy");output=== Anonymous Classes === --- Implementing Interface ---@Override public void greet(String name)
72Greeting formalGreeting = new Greeting() { //?formalgreeting73 @Override74 public void greet(String nameSir) {75 System.out.println("Good day, " + nameSir + ". How do you do?");76 }outputGood day, Sir. How do you do?formalGreeting.greet("Sir");
86formalGreeting.greet("Sir");87casualGreeting.greet("buddy");@Override public void greet(String name)
79Greeting casualGreeting = new Greeting() { //?casualgreeting80 @Override81 public void greet(String namebuddy) {82 System.out.println("Hey " + namebuddy + "! What's up?");83 }outputHey buddy! What's up?dog ← ⟨AnonymousClass$3 C⟩, cat ← ⟨AnonymousClass$4 D⟩
86formalGreeting.greet("Sir");87casualGreeting.greet("buddy");8889// Anonymous class extending abstract class //?anonabstract90System.out.println("\n--- Extending Abstract Class ---");91Animal dog→ ⟨AnonymousClass$3 C⟩ = new Animal() { //?doganimous92 @Override93 void makeSound() {94 System.out.println("Woof woof!");95 }96};9798Animal cat→ ⟨AnonymousClass$4 D⟩ = new Animal() {99 @Override100 void makeSound() {101 System.out.println("Meow!");102 }103 104 // Can add new methods, but can't call via Animal reference //?newmethod105 void purr() {106 System.out.println("Purrrr...");107 }108};109110dog.makeSound();111dog.sleep(); // Inherited methodoutput --- Extending Abstract Class ---@Override void makeSound()
91Animal dog = new Animal() { //?doganimous92 @Override93 void makeSound() {94 System.out.println("Woof woof!");95 }outputWoof woof!dog.makeSound();
110dog.makeSound();111dog.sleep(); // Inherited methodvoid sleep()
15void sleep() {16 System.out.println("Zzz...");17}outputZzz...dog.sleep(); // Inherited method
110dog.makeSound();111dog.sleep(); // Inherited method112113cat.makeSound();114// cat.purr(); // Cannot call - Animal doesn't have purr()@Override void makeSound()
98Animal cat = new Animal() {99 @Override100 void makeSound() {101 System.out.println("Meow!");102 }outputMeow!words ← [cat, elephant, dog, butterfly], sorter ← ⟨SortingDemo E⟩
113cat.makeSound();114// cat.purr(); // Cannot call - Animal doesn't have purr()115116// Sorting with anonymous Comparator //?sortingdemo117System.out.println("\n--- Sorting with Anonymous Comparator ---");118List<String> words→ [cat, elephant, dog, butterfly] = new ArrayList<>(List.of("cat", "elephant", "dog", "butterfly"));119120System.out.println("Original: " + words[cat, elephant, dog, butterfly]);121122SortingDemo sorter→ ⟨SortingDemo E⟩ = new SortingDemo();123sorter.sortStrings(words[cat, elephant, dog, butterfly]);124System.out.println("By length: " + words);output --- Sorting with Anonymous Comparator --- Original: [cat, elephant, dog, butterfly]lengthComparator ← ⟨SortingDemo$1 F⟩
22// Using anonymous class for Comparator //?comparatordemo23public void sortStrings(List<String> strings[cat, elephant, dog, butterfly]) {24 // Anonymous class implementing Comparator //?anonymouscomparator25 Comparator<String> lengthComparator→ ⟨SortingDemo$1 F⟩ = new Comparator<String>() { //?anonymousdefinition26 @Override27 public int compare(String s1, String s2) {28 return Integer.compare(s1.length(), s2.length());29 }30 }; //?semicolon31 32 Collections.sort(strings[cat, elephant, dog, butterfly], lengthComparator⟨SortingDemo$1 F⟩);33}@Override public int compare(String s1, String s2)
pass 1 of 625Comparator<String> lengthComparator = new Comparator<String>() { //?anonymousdefinition26 @Override27 public int compare(String s1elephant, String s2cat) {28 return Integer.compare(s1.length(), s2.length());29 }All 6 passes — pass 1 is the card above pass s1s21 elephant cat 2 dog elephant 3 dog elephant 4 dog cat 5 butterfly dog 6 butterfly elephant strings ← [cat, dog, elephant, butterfly]
32 Collections.sort(strings→ [cat, dog, elephant, butterfly], lengthComparator⟨SortingDemo$1 F⟩);33}words ← [cat, dog, elephant, butterfly]
122SortingDemo sorter = new SortingDemo();123sorter.sortStrings(words→ [cat, dog, elephant, butterfly]);124System.out.println("By length: " + words[cat, dog, elephant, butterfly]);125126words→ [cat, elephant, dog, butterfly] = new ArrayList<>(List.of("cat", "elephant", "dog", "butterfly"));127sorter.sortByLastChar(words[cat, elephant, dog, butterfly]);128System.out.println("By last char: " + words);outputBy length: [cat, dog, elephant, butterfly]public void sortByLastChar(List<String> strings)
35// Anonymous class inline //?inlineanonymous36public void sortByLastChar(List<String> strings[cat, elephant, dog, butterfly]) {37 Collections.sort(strings[cat, elephant, dog, butterfly], new Comparator<String>() { //?inlinedef38 @Override39 public int compare(String s1, String s2) {40 char last1 = s1.charAt(s1.length() - 1);41 char last2 = s2.charAt(s2.length() - 1);42 return Character.compare(last1, last2);43 }44 });45}last1 ← t, last2 ← t
pass 1 of 637Collections.sort(strings, new Comparator<String>() { //?inlinedef38 @Override39 public int compare(String s1elephant, String s2cat) {40 char last1→ t = s1.charAt(s1.length() - 1);41 char last2→ t = s2.charAt(s2.length() - 1);42 return Character.compare(last1t, last2t);43 }All 6 passes — pass 1 is the card above pass s1s2last1last21 elephant cat t t 2 dog elephant g t 3 dog elephant g t 4 dog cat g t 5 butterfly cat y t 6 butterfly elephant y t strings ← [dog, cat, elephant, butterfly]
36public void sortByLastChar(List<String> strings) {37 Collections.sort(strings→ [dog, cat, elephant, butterfly], new Comparator<String>() { //?inlinedef38 @Override39 public int compare(String s1, String s2) {40 char last1 = s1.charAt(s1.length() - 1);41 char last2 = s2.charAt(s2.length() - 1);42 return Character.compare(last1, last2);43 }44 });45}words ← [dog, cat, elephant, butterfly], button ← ⟨ButtonSimulator G⟩
126words = new ArrayList<>(List.of("cat", "elephant", "dog", "butterfly"));127sorter.sortByLastChar(words→ [dog, cat, elephant, butterfly]);128System.out.println("By last char: " + words[dog, cat, elephant, butterfly]);129130// Event listener pattern //?eventpattern131System.out.println("\n--- Event Listener Pattern ---");132ButtonSimulator button→ ⟨ButtonSimulator G⟩ = new ButtonSimulator();133134button.setOnClickListener(new ButtonSimulator.ClickListener() { //?buttonlistener135 private int clickCount = 0; // Anonymous class can have state! //?anonstate136 137 @Override138 public void onClick() {139 clickCount++;140 System.out.println("Button clicked! Count: " + clickCount);141 }142});outputBy last char: [dog, cat, elephant, butterfly] --- Event Listener Pattern ---this.listener ← ⟨AnonymousClass$5 H⟩
55public void setOnClickListener(ClickListener listener⟨AnonymousClass$5 H⟩) {56 this.listener→ ⟨AnonymousClass$5 H⟩ = listener⟨AnonymousClass$5 H⟩;57}button.setOnClickListener(new ButtonSimulator.ClickListener() { //?but…
134button.setOnClickListener(new ButtonSimulator.ClickListener() { //?buttonlistener135 private int clickCount = 0; // Anonymous class can have state! //?anonstate136 137 @Override138 public void onClick() {139 clickCount++;140 System.out.println("Button clicked! Count: " + clickCount);141 }142});143144button.click();145button.click();if (listener != null)
pass 1 of 359public void click() {60 if (listener⟨AnonymousClass$5 H⟩ != null) {61 listener.onClick();62 }clickCount ← 1
pass 1 of 360 if (listener != null) {61 listener.onClick();62 }63 }64}6566public class AnonymousClass {67 public static void main(String[] args) {68 System.out.println("=== Anonymous Classes ===\n");69 70 // Anonymous class implementing interface //?anoninterface71 System.out.println("--- Implementing Interface ---");72 Greeting formalGreeting = new Greeting() { //?formalgreeting73 @Override74 public void greet(String name) {75 System.out.println("Good day, " + name + ". How do you do?");76 }77 };78 79 Greeting casualGreeting = new Greeting() { //?casualgreeting80 @Override81 public void greet(String name) {82 System.out.println("Hey " + name + "! What's up?");83 }84 };85 86 formalGreeting.greet("Sir");87 casualGreeting.greet("buddy");88 89 // Anonymous class extending abstract class //?anonabstract90 System.out.println("\n--- Extending Abstract Class ---");91 Animal dog = new Animal() { //?doganimous92 @Override93 void makeSound() {94 System.out.println("Woof woof!");95 }96 };97 98 Animal cat = new Animal() {99 @Override100 void makeSound() {101 System.out.println("Meow!");102 }103 104 // Can add new methods, but can't call via Animal reference //?newmethod105 void purr() {106 System.out.println("Purrrr...");107 }108 };109 110 dog.makeSound();111 dog.sleep(); // Inherited method112 113 cat.makeSound();114 // cat.purr(); // Cannot call - Animal doesn't have purr()115 116 // Sorting with anonymous Comparator //?sortingdemo117 System.out.println("\n--- Sorting with Anonymous Comparator ---");118 List<String> words = new ArrayList<>(List.of("cat", "elephant", "dog", "butterfly"));119 120 System.out.println("Original: " + words);121 122 SortingDemo sorter = new SortingDemo();123 sorter.sortStrings(words);124 System.out.println("By length: " + words);125 126 words = new ArrayList<>(List.of("cat", "elephant", "dog", "butterfly"));127 sorter.sortByLastChar(words);128 System.out.println("By last char: " + words);129 130 // Event listener pattern //?eventpattern131 System.out.println("\n--- Event Listener Pattern ---");132 ButtonSimulator button = new ButtonSimulator();133 134 button.setOnClickListener(new ButtonSimulator.ClickListener() { //?buttonlistener135 private int clickCount = 0; // Anonymous class can have state! //?anonstate136 137 @Override138 public void onClick() {139 clickCount→ 1++;140 System.out.println("Button clicked! Count: " + clickCount1);141 }outputButton clicked! Count: 1All 3 passes — pass 1 is the card above pass clickCount1 0 → 1 2 1 → 2 3 2 → 3 button.click();
144button.click();145button.click();146button.click();button.click();
144button.click();145button.click();146button.click();message ← Hello, times ← 3, printer ← ⟨AnonymousClass$6 I⟩
145button.click();146button.click();147148// Capturing local variables //?capturevars149System.out.println("\n--- Capturing Local Variables ---");150String message→ Hello = "Hello"; // Effectively final //?effectivelyfinal151int times→ 3 = 3; //@times=3, 1, 5152153Runnable printer→ ⟨AnonymousClass$6 I⟩ = new Runnable() { //?runnable154 @Override155 public void run() {156 for (int i = 0; i < times; i++) {157 System.out.println(message);158 }159 }160};161162printer.run();output --- Capturing Local Variables ---for (int i = 0; i < times; i++)
pass 1 of 3155public void run() {156 for (int i0 = 0; i < times3; i++) {157 System.out.println(messageHello);158 }outputHelloAll 3 passes — pass 1 is the card above pass i1 0 2 1 3 2 printer.run();
162 printer.run();163 164 // message = "Changed"; // Would cause error - breaks effectively final165 166 System.out.println("\n=== Anonymous Class Rules ===");167 System.out.println("""168 1. No name - defined and instantiated in one expression169 2. Implements interface OR extends class (not both)170 3. Must end with semicolon after closing brace171 4. Cannot have explicit constructor172 5. Can have instance fields and methods173 6. Can capture effectively final local variables174 175 Syntax:176 new Interface() { ... };177 new ClassName(args) { ... };178 179 When to use:180 - One-time implementation needed181 - Simple interface (1-2 methods)182 - Event listeners/callbacks183 184 Modern alternative: Lambda expressions (for single-method interfaces)185 """);186}output === Anonymous Class Rules === 1. No name - defined and instantiated in one expression 2. Implements interface OR extends class (not both) 3. Must end with semicolon after closing brace 4. Cannot have explicit constructor 5. Can have instance fields and methods 6. Can capture effectively final local variables Syntax: new Interface() { ... }; new ClassName(args) { ... }; When to use: - One-time implementation needed - Simple interface (1-2 methods) - Event listeners/callbacks Modern alternative: Lambda expressions (for single-method interfaces)
formalGreeting ← ⟨AnonymousClass$1 A⟩, casualGreeting ← ⟨AnonymousClass$2 B⟩
66public class AnonymousClass {67 public static void main(String[] args) {68 System.out.println("=== Anonymous Classes ===\n");69 70 // Anonymous class implementing interface71 System.out.println("--- Implementing Interface ---");72 Greeting formalGreeting→ ⟨AnonymousClass$1 A⟩ = new Greeting() {73 @Override74 public void greet(String name) {75 System.out.println("Good day, " + name + ". How do you do?");76 }77 };78 79 Greeting casualGreeting→ ⟨AnonymousClass$2 B⟩ = new Greeting() {80 @Override81 public void greet(String name) {82 System.out.println("Hey " + name + "! What's up?");83 }84 };85 86 formalGreeting.greet("Sir");87 casualGreeting.greet("buddy");output=== Anonymous Classes === --- Implementing Interface ---@Override public void greet(String name)
72Greeting formalGreeting = new Greeting() {73 @Override74 public void greet(String nameSir) {75 System.out.println("Good day, " + nameSir + ". How do you do?");76 }outputGood day, Sir. How do you do?formalGreeting.greet("Sir");
86formalGreeting.greet("Sir");87casualGreeting.greet("buddy");@Override public void greet(String name)
79Greeting casualGreeting = new Greeting() {80 @Override81 public void greet(String namebuddy) {82 System.out.println("Hey " + namebuddy + "! What's up?");83 }outputHey buddy! What's up?dog ← ⟨AnonymousClass$3 C⟩, cat ← ⟨AnonymousClass$4 D⟩
86formalGreeting.greet("Sir");87casualGreeting.greet("buddy");8889// Anonymous class extending abstract class90System.out.println("\n--- Extending Abstract Class ---");91Animal dog→ ⟨AnonymousClass$3 C⟩ = new Animal() {92 @Override93 void makeSound() {94 System.out.println("Woof woof!");95 }96};9798Animal cat→ ⟨AnonymousClass$4 D⟩ = new Animal() {99 @Override100 void makeSound() {101 System.out.println("Meow!");102 }103 104 // Can add new methods, but can't call via Animal reference105 void purr() {106 System.out.println("Purrrr...");107 }108};109110dog.makeSound();111dog.sleep(); // Inherited methodoutput --- Extending Abstract Class ---@Override void makeSound()
91Animal dog = new Animal() {92 @Override93 void makeSound() {94 System.out.println("Woof woof!");95 }outputWoof woof!dog.makeSound();
110dog.makeSound();111dog.sleep(); // Inherited methodvoid sleep()
15void sleep() {16 System.out.println("Zzz...");17}outputZzz...dog.sleep(); // Inherited method
110dog.makeSound();111dog.sleep(); // Inherited method112113cat.makeSound();114// cat.purr(); // Cannot call - Animal doesn't have purr()@Override void makeSound()
98Animal cat = new Animal() {99 @Override100 void makeSound() {101 System.out.println("Meow!");102 }outputMeow!words ← [cat, elephant, dog, butterfly], sorter ← ⟨SortingDemo E⟩
113cat.makeSound();114// cat.purr(); // Cannot call - Animal doesn't have purr()115116// Sorting with anonymous Comparator117System.out.println("\n--- Sorting with Anonymous Comparator ---");118List<String> words→ [cat, elephant, dog, butterfly] = new ArrayList<>(List.of("cat", "elephant", "dog", "butterfly"));119120System.out.println("Original: " + words[cat, elephant, dog, butterfly]);121122SortingDemo sorter→ ⟨SortingDemo E⟩ = new SortingDemo();123sorter.sortStrings(words[cat, elephant, dog, butterfly]);124System.out.println("By length: " + words);output --- Sorting with Anonymous Comparator --- Original: [cat, elephant, dog, butterfly]lengthComparator ← ⟨SortingDemo$1 F⟩
22// Using anonymous class for Comparator23public void sortStrings(List<String> strings[cat, elephant, dog, butterfly]) {24 // Anonymous class implementing Comparator25 Comparator<String> lengthComparator→ ⟨SortingDemo$1 F⟩ = new Comparator<String>() {26 @Override27 public int compare(String s1, String s2) {28 return Integer.compare(s1.length(), s2.length());29 }30 };31 32 Collections.sort(strings[cat, elephant, dog, butterfly], lengthComparator⟨SortingDemo$1 F⟩);33}@Override public int compare(String s1, String s2)
pass 1 of 625Comparator<String> lengthComparator = new Comparator<String>() {26 @Override27 public int compare(String s1elephant, String s2cat) {28 return Integer.compare(s1.length(), s2.length());29 }All 6 passes — pass 1 is the card above pass s1s21 elephant cat 2 dog elephant 3 dog elephant 4 dog cat 5 butterfly dog 6 butterfly elephant strings ← [cat, dog, elephant, butterfly]
32 Collections.sort(strings→ [cat, dog, elephant, butterfly], lengthComparator⟨SortingDemo$1 F⟩);33}words ← [cat, dog, elephant, butterfly]
122SortingDemo sorter = new SortingDemo();123sorter.sortStrings(words→ [cat, dog, elephant, butterfly]);124System.out.println("By length: " + words[cat, dog, elephant, butterfly]);125126words→ [cat, elephant, dog, butterfly] = new ArrayList<>(List.of("cat", "elephant", "dog", "butterfly"));127sorter.sortByLastChar(words[cat, elephant, dog, butterfly]);128System.out.println("By last char: " + words);outputBy length: [cat, dog, elephant, butterfly]public void sortByLastChar(List<String> strings)
35// Anonymous class inline36public void sortByLastChar(List<String> strings[cat, elephant, dog, butterfly]) {37 Collections.sort(strings[cat, elephant, dog, butterfly], new Comparator<String>() {38 @Override39 public int compare(String s1, String s2) {40 char last1 = s1.charAt(s1.length() - 1);41 char last2 = s2.charAt(s2.length() - 1);42 return Character.compare(last1, last2);43 }44 });45}last1 ← t, last2 ← t
pass 1 of 637Collections.sort(strings, new Comparator<String>() {38 @Override39 public int compare(String s1elephant, String s2cat) {40 char last1→ t = s1.charAt(s1.length() - 1);41 char last2→ t = s2.charAt(s2.length() - 1);42 return Character.compare(last1t, last2t);43 }All 6 passes — pass 1 is the card above pass s1s2last1last21 elephant cat t t 2 dog elephant g t 3 dog elephant g t 4 dog cat g t 5 butterfly cat y t 6 butterfly elephant y t strings ← [dog, cat, elephant, butterfly]
36public void sortByLastChar(List<String> strings) {37 Collections.sort(strings→ [dog, cat, elephant, butterfly], new Comparator<String>() {38 @Override39 public int compare(String s1, String s2) {40 char last1 = s1.charAt(s1.length() - 1);41 char last2 = s2.charAt(s2.length() - 1);42 return Character.compare(last1, last2);43 }44 });45}words ← [dog, cat, elephant, butterfly], button ← ⟨ButtonSimulator G⟩
126words = new ArrayList<>(List.of("cat", "elephant", "dog", "butterfly"));127sorter.sortByLastChar(words→ [dog, cat, elephant, butterfly]);128System.out.println("By last char: " + words[dog, cat, elephant, butterfly]);129130// Event listener pattern131System.out.println("\n--- Event Listener Pattern ---");132ButtonSimulator button→ ⟨ButtonSimulator G⟩ = new ButtonSimulator();133134button.setOnClickListener(new ButtonSimulator.ClickListener() {135 private int clickCount = 0; // Anonymous class can have state!136 137 @Override138 public void onClick() {139 clickCount++;140 System.out.println("Button clicked! Count: " + clickCount);141 }142});outputBy last char: [dog, cat, elephant, butterfly] --- Event Listener Pattern ---this.listener ← ⟨AnonymousClass$5 H⟩
55public void setOnClickListener(ClickListener listener⟨AnonymousClass$5 H⟩) {56 this.listener→ ⟨AnonymousClass$5 H⟩ = listener⟨AnonymousClass$5 H⟩;57}button.setOnClickListener(new ButtonSimulator.ClickListener()
134button.setOnClickListener(new ButtonSimulator.ClickListener() {135 private int clickCount = 0; // Anonymous class can have state!136 137 @Override138 public void onClick() {139 clickCount++;140 System.out.println("Button clicked! Count: " + clickCount);141 }142});143144button.click();145button.click();if (listener != null)
pass 1 of 359public void click() {60 if (listener⟨AnonymousClass$5 H⟩ != null) {61 listener.onClick();62 }clickCount ← 1
pass 1 of 360 if (listener != null) {61 listener.onClick();62 }63 }64}6566public class AnonymousClass {67 public static void main(String[] args) {68 System.out.println("=== Anonymous Classes ===\n");69 70 // Anonymous class implementing interface71 System.out.println("--- Implementing Interface ---");72 Greeting formalGreeting = new Greeting() {73 @Override74 public void greet(String name) {75 System.out.println("Good day, " + name + ". How do you do?");76 }77 };78 79 Greeting casualGreeting = new Greeting() {80 @Override81 public void greet(String name) {82 System.out.println("Hey " + name + "! What's up?");83 }84 };85 86 formalGreeting.greet("Sir");87 casualGreeting.greet("buddy");88 89 // Anonymous class extending abstract class90 System.out.println("\n--- Extending Abstract Class ---");91 Animal dog = new Animal() {92 @Override93 void makeSound() {94 System.out.println("Woof woof!");95 }96 };97 98 Animal cat = new Animal() {99 @Override100 void makeSound() {101 System.out.println("Meow!");102 }103 104 // Can add new methods, but can't call via Animal reference105 void purr() {106 System.out.println("Purrrr...");107 }108 };109 110 dog.makeSound();111 dog.sleep(); // Inherited method112 113 cat.makeSound();114 // cat.purr(); // Cannot call - Animal doesn't have purr()115 116 // Sorting with anonymous Comparator117 System.out.println("\n--- Sorting with Anonymous Comparator ---");118 List<String> words = new ArrayList<>(List.of("cat", "elephant", "dog", "butterfly"));119 120 System.out.println("Original: " + words);121 122 SortingDemo sorter = new SortingDemo();123 sorter.sortStrings(words);124 System.out.println("By length: " + words);125 126 words = new ArrayList<>(List.of("cat", "elephant", "dog", "butterfly"));127 sorter.sortByLastChar(words);128 System.out.println("By last char: " + words);129 130 // Event listener pattern131 System.out.println("\n--- Event Listener Pattern ---");132 ButtonSimulator button = new ButtonSimulator();133 134 button.setOnClickListener(new ButtonSimulator.ClickListener() {135 private int clickCount = 0; // Anonymous class can have state!136 137 @Override138 public void onClick() {139 clickCount→ 1++;140 System.out.println("Button clicked! Count: " + clickCount1);141 }outputButton clicked! Count: 1All 3 passes — pass 1 is the card above pass clickCount1 0 → 1 2 1 → 2 3 2 → 3 button.click();
144button.click();145button.click();146button.click();button.click();
144button.click();145button.click();146button.click();message ← Hello, times ← 1, printer ← ⟨AnonymousClass$6 I⟩
145button.click();146button.click();147148// Capturing local variables149System.out.println("\n--- Capturing Local Variables ---");150String message→ Hello = "Hello"; // Effectively final151int times→ 1 = 1;152153Runnable printer→ ⟨AnonymousClass$6 I⟩ = new Runnable() {154 @Override155 public void run() {156 for (int i = 0; i < times; i++) {157 System.out.println(message);158 }159 }160};161162printer.run();output --- Capturing Local Variables ---for (int i = 0; i < times; i++)
155public void run() {156 for (int i0 = 0; i < times1; i++) {157 System.out.println(messageHello);158 }outputHelloprinter.run();
162 printer.run();163 164 // message = "Changed"; // Would cause error - breaks effectively final165 166 System.out.println("\n=== Anonymous Class Rules ===");167 System.out.println("""168 1. No name - defined and instantiated in one expression169 2. Implements interface OR extends class (not both)170 3. Must end with semicolon after closing brace171 4. Cannot have explicit constructor172 5. Can have instance fields and methods173 6. Can capture effectively final local variables174 175 Syntax:176 new Interface() { ... };177 new ClassName(args) { ... };178 179 When to use:180 - One-time implementation needed181 - Simple interface (1-2 methods)182 - Event listeners/callbacks183 184 Modern alternative: Lambda expressions (for single-method interfaces)185 """);186}output === Anonymous Class Rules === 1. No name - defined and instantiated in one expression 2. Implements interface OR extends class (not both) 3. Must end with semicolon after closing brace 4. Cannot have explicit constructor 5. Can have instance fields and methods 6. Can capture effectively final local variables Syntax: new Interface() { ... }; new ClassName(args) { ... }; When to use: - One-time implementation needed - Simple interface (1-2 methods) - Event listeners/callbacks Modern alternative: Lambda expressions (for single-method interfaces)
formalGreeting ← ⟨AnonymousClass$1 A⟩, casualGreeting ← ⟨AnonymousClass$2 B⟩
66public class AnonymousClass {67 public static void main(String[] args) {68 System.out.println("=== Anonymous Classes ===\n");69 70 // Anonymous class implementing interface71 System.out.println("--- Implementing Interface ---");72 Greeting formalGreeting→ ⟨AnonymousClass$1 A⟩ = new Greeting() {73 @Override74 public void greet(String name) {75 System.out.println("Good day, " + name + ". How do you do?");76 }77 };78 79 Greeting casualGreeting→ ⟨AnonymousClass$2 B⟩ = new Greeting() {80 @Override81 public void greet(String name) {82 System.out.println("Hey " + name + "! What's up?");83 }84 };85 86 formalGreeting.greet("Sir");87 casualGreeting.greet("buddy");output=== Anonymous Classes === --- Implementing Interface ---@Override public void greet(String name)
72Greeting formalGreeting = new Greeting() {73 @Override74 public void greet(String nameSir) {75 System.out.println("Good day, " + nameSir + ". How do you do?");76 }outputGood day, Sir. How do you do?formalGreeting.greet("Sir");
86formalGreeting.greet("Sir");87casualGreeting.greet("buddy");@Override public void greet(String name)
79Greeting casualGreeting = new Greeting() {80 @Override81 public void greet(String namebuddy) {82 System.out.println("Hey " + namebuddy + "! What's up?");83 }outputHey buddy! What's up?dog ← ⟨AnonymousClass$3 C⟩, cat ← ⟨AnonymousClass$4 D⟩
86formalGreeting.greet("Sir");87casualGreeting.greet("buddy");8889// Anonymous class extending abstract class90System.out.println("\n--- Extending Abstract Class ---");91Animal dog→ ⟨AnonymousClass$3 C⟩ = new Animal() {92 @Override93 void makeSound() {94 System.out.println("Woof woof!");95 }96};9798Animal cat→ ⟨AnonymousClass$4 D⟩ = new Animal() {99 @Override100 void makeSound() {101 System.out.println("Meow!");102 }103 104 // Can add new methods, but can't call via Animal reference105 void purr() {106 System.out.println("Purrrr...");107 }108};109110dog.makeSound();111dog.sleep(); // Inherited methodoutput --- Extending Abstract Class ---@Override void makeSound()
91Animal dog = new Animal() {92 @Override93 void makeSound() {94 System.out.println("Woof woof!");95 }outputWoof woof!dog.makeSound();
110dog.makeSound();111dog.sleep(); // Inherited methodvoid sleep()
15void sleep() {16 System.out.println("Zzz...");17}outputZzz...dog.sleep(); // Inherited method
110dog.makeSound();111dog.sleep(); // Inherited method112113cat.makeSound();114// cat.purr(); // Cannot call - Animal doesn't have purr()@Override void makeSound()
98Animal cat = new Animal() {99 @Override100 void makeSound() {101 System.out.println("Meow!");102 }outputMeow!words ← [cat, elephant, dog, butterfly], sorter ← ⟨SortingDemo E⟩
113cat.makeSound();114// cat.purr(); // Cannot call - Animal doesn't have purr()115116// Sorting with anonymous Comparator117System.out.println("\n--- Sorting with Anonymous Comparator ---");118List<String> words→ [cat, elephant, dog, butterfly] = new ArrayList<>(List.of("cat", "elephant", "dog", "butterfly"));119120System.out.println("Original: " + words[cat, elephant, dog, butterfly]);121122SortingDemo sorter→ ⟨SortingDemo E⟩ = new SortingDemo();123sorter.sortStrings(words[cat, elephant, dog, butterfly]);124System.out.println("By length: " + words);output --- Sorting with Anonymous Comparator --- Original: [cat, elephant, dog, butterfly]lengthComparator ← ⟨SortingDemo$1 F⟩
22// Using anonymous class for Comparator23public void sortStrings(List<String> strings[cat, elephant, dog, butterfly]) {24 // Anonymous class implementing Comparator25 Comparator<String> lengthComparator→ ⟨SortingDemo$1 F⟩ = new Comparator<String>() {26 @Override27 public int compare(String s1, String s2) {28 return Integer.compare(s1.length(), s2.length());29 }30 };31 32 Collections.sort(strings[cat, elephant, dog, butterfly], lengthComparator⟨SortingDemo$1 F⟩);33}@Override public int compare(String s1, String s2)
pass 1 of 625Comparator<String> lengthComparator = new Comparator<String>() {26 @Override27 public int compare(String s1elephant, String s2cat) {28 return Integer.compare(s1.length(), s2.length());29 }All 6 passes — pass 1 is the card above pass s1s21 elephant cat 2 dog elephant 3 dog elephant 4 dog cat 5 butterfly dog 6 butterfly elephant strings ← [cat, dog, elephant, butterfly]
32 Collections.sort(strings→ [cat, dog, elephant, butterfly], lengthComparator⟨SortingDemo$1 F⟩);33}words ← [cat, dog, elephant, butterfly]
122SortingDemo sorter = new SortingDemo();123sorter.sortStrings(words→ [cat, dog, elephant, butterfly]);124System.out.println("By length: " + words[cat, dog, elephant, butterfly]);125126words→ [cat, elephant, dog, butterfly] = new ArrayList<>(List.of("cat", "elephant", "dog", "butterfly"));127sorter.sortByLastChar(words[cat, elephant, dog, butterfly]);128System.out.println("By last char: " + words);outputBy length: [cat, dog, elephant, butterfly]public void sortByLastChar(List<String> strings)
35// Anonymous class inline36public void sortByLastChar(List<String> strings[cat, elephant, dog, butterfly]) {37 Collections.sort(strings[cat, elephant, dog, butterfly], new Comparator<String>() {38 @Override39 public int compare(String s1, String s2) {40 char last1 = s1.charAt(s1.length() - 1);41 char last2 = s2.charAt(s2.length() - 1);42 return Character.compare(last1, last2);43 }44 });45}last1 ← t, last2 ← t
pass 1 of 637Collections.sort(strings, new Comparator<String>() {38 @Override39 public int compare(String s1elephant, String s2cat) {40 char last1→ t = s1.charAt(s1.length() - 1);41 char last2→ t = s2.charAt(s2.length() - 1);42 return Character.compare(last1t, last2t);43 }All 6 passes — pass 1 is the card above pass s1s2last1last21 elephant cat t t 2 dog elephant g t 3 dog elephant g t 4 dog cat g t 5 butterfly cat y t 6 butterfly elephant y t strings ← [dog, cat, elephant, butterfly]
36public void sortByLastChar(List<String> strings) {37 Collections.sort(strings→ [dog, cat, elephant, butterfly], new Comparator<String>() {38 @Override39 public int compare(String s1, String s2) {40 char last1 = s1.charAt(s1.length() - 1);41 char last2 = s2.charAt(s2.length() - 1);42 return Character.compare(last1, last2);43 }44 });45}words ← [dog, cat, elephant, butterfly], button ← ⟨ButtonSimulator G⟩
126words = new ArrayList<>(List.of("cat", "elephant", "dog", "butterfly"));127sorter.sortByLastChar(words→ [dog, cat, elephant, butterfly]);128System.out.println("By last char: " + words[dog, cat, elephant, butterfly]);129130// Event listener pattern131System.out.println("\n--- Event Listener Pattern ---");132ButtonSimulator button→ ⟨ButtonSimulator G⟩ = new ButtonSimulator();133134button.setOnClickListener(new ButtonSimulator.ClickListener() {135 private int clickCount = 0; // Anonymous class can have state!136 137 @Override138 public void onClick() {139 clickCount++;140 System.out.println("Button clicked! Count: " + clickCount);141 }142});outputBy last char: [dog, cat, elephant, butterfly] --- Event Listener Pattern ---this.listener ← ⟨AnonymousClass$5 H⟩
55public void setOnClickListener(ClickListener listener⟨AnonymousClass$5 H⟩) {56 this.listener→ ⟨AnonymousClass$5 H⟩ = listener⟨AnonymousClass$5 H⟩;57}button.setOnClickListener(new ButtonSimulator.ClickListener()
134button.setOnClickListener(new ButtonSimulator.ClickListener() {135 private int clickCount = 0; // Anonymous class can have state!136 137 @Override138 public void onClick() {139 clickCount++;140 System.out.println("Button clicked! Count: " + clickCount);141 }142});143144button.click();145button.click();if (listener != null)
pass 1 of 359public void click() {60 if (listener⟨AnonymousClass$5 H⟩ != null) {61 listener.onClick();62 }clickCount ← 1
pass 1 of 360 if (listener != null) {61 listener.onClick();62 }63 }64}6566public class AnonymousClass {67 public static void main(String[] args) {68 System.out.println("=== Anonymous Classes ===\n");69 70 // Anonymous class implementing interface71 System.out.println("--- Implementing Interface ---");72 Greeting formalGreeting = new Greeting() {73 @Override74 public void greet(String name) {75 System.out.println("Good day, " + name + ". How do you do?");76 }77 };78 79 Greeting casualGreeting = new Greeting() {80 @Override81 public void greet(String name) {82 System.out.println("Hey " + name + "! What's up?");83 }84 };85 86 formalGreeting.greet("Sir");87 casualGreeting.greet("buddy");88 89 // Anonymous class extending abstract class90 System.out.println("\n--- Extending Abstract Class ---");91 Animal dog = new Animal() {92 @Override93 void makeSound() {94 System.out.println("Woof woof!");95 }96 };97 98 Animal cat = new Animal() {99 @Override100 void makeSound() {101 System.out.println("Meow!");102 }103 104 // Can add new methods, but can't call via Animal reference105 void purr() {106 System.out.println("Purrrr...");107 }108 };109 110 dog.makeSound();111 dog.sleep(); // Inherited method112 113 cat.makeSound();114 // cat.purr(); // Cannot call - Animal doesn't have purr()115 116 // Sorting with anonymous Comparator117 System.out.println("\n--- Sorting with Anonymous Comparator ---");118 List<String> words = new ArrayList<>(List.of("cat", "elephant", "dog", "butterfly"));119 120 System.out.println("Original: " + words);121 122 SortingDemo sorter = new SortingDemo();123 sorter.sortStrings(words);124 System.out.println("By length: " + words);125 126 words = new ArrayList<>(List.of("cat", "elephant", "dog", "butterfly"));127 sorter.sortByLastChar(words);128 System.out.println("By last char: " + words);129 130 // Event listener pattern131 System.out.println("\n--- Event Listener Pattern ---");132 ButtonSimulator button = new ButtonSimulator();133 134 button.setOnClickListener(new ButtonSimulator.ClickListener() {135 private int clickCount = 0; // Anonymous class can have state!136 137 @Override138 public void onClick() {139 clickCount→ 1++;140 System.out.println("Button clicked! Count: " + clickCount1);141 }outputButton clicked! Count: 1All 3 passes — pass 1 is the card above pass clickCount1 0 → 1 2 1 → 2 3 2 → 3 button.click();
144button.click();145button.click();146button.click();button.click();
144button.click();145button.click();146button.click();message ← Hello, times ← 5, printer ← ⟨AnonymousClass$6 I⟩
145button.click();146button.click();147148// Capturing local variables149System.out.println("\n--- Capturing Local Variables ---");150String message→ Hello = "Hello"; // Effectively final151int times→ 5 = 5;152153Runnable printer→ ⟨AnonymousClass$6 I⟩ = new Runnable() {154 @Override155 public void run() {156 for (int i = 0; i < times; i++) {157 System.out.println(message);158 }159 }160};161162printer.run();output --- Capturing Local Variables ---for (int i = 0; i < times; i++)
pass 1 of 5155public void run() {156 for (int i0 = 0; i < times5; i++) {157 System.out.println(messageHello);158 }outputHelloAll 5 passes — pass 1 is the card above pass i1 0 2 1 3 2 4 3 5 4 printer.run();
162 printer.run();163 164 // message = "Changed"; // Would cause error - breaks effectively final165 166 System.out.println("\n=== Anonymous Class Rules ===");167 System.out.println("""168 1. No name - defined and instantiated in one expression169 2. Implements interface OR extends class (not both)170 3. Must end with semicolon after closing brace171 4. Cannot have explicit constructor172 5. Can have instance fields and methods173 6. Can capture effectively final local variables174 175 Syntax:176 new Interface() { ... };177 new ClassName(args) { ... };178 179 When to use:180 - One-time implementation needed181 - Simple interface (1-2 methods)182 - Event listeners/callbacks183 184 Modern alternative: Lambda expressions (for single-method interfaces)185 """);186}output === Anonymous Class Rules === 1. No name - defined and instantiated in one expression 2. Implements interface OR extends class (not both) 3. Must end with semicolon after closing brace 4. Cannot have explicit constructor 5. Can have instance fields and methods 6. Can capture effectively final local variables Syntax: new Interface() { ... }; new ClassName(args) { ... }; When to use: - One-time implementation needed - Simple interface (1-2 methods) - Event listeners/callbacks Modern alternative: Lambda expressions (for single-method interfaces)
new Interface() { } creates anonymous implementation. Common for callbacks.
Common patterns
Where inner classes shine.
// Common Inner Class Patterns
import java.util.Iterator;
import java.util.NoSuchElementException;
// Pattern 1: Iterator pattern
class NumberRange implements Iterable<Integer> {
private final int start;
private final int end;
NumberRange(int start, int end) {
this.start = start;
this.end = end;
}
@Override
public Iterator<Integer> iterator() {
return new RangeIterator();
}
// Private inner class for iterator
private class RangeIterator implements Iterator<Integer> {
private int current = start; // Uses outer's start
@Override
public boolean hasNext() {
return current <= end; // Uses outer's end
}
@Override
public Integer next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return current++;
}
}
}
// Pattern 2: Callback/Handler with state
class TaskRunner {
interface TaskCallback {
void onProgress(int percent);
void onComplete(String result);
void onError(String error);
}
public void runTask(String taskName, TaskCallback callback) {
System.out.println("Starting task: " + taskName);
// Simulate progress
for (int i = 0; i <= 100; i += 25) {
callback.onProgress(i);
}
callback.onComplete("Task completed successfully!");
}
}
// Pattern 3: Type-safe constants with behavior
class Operation {
private final String symbol;
private Operation(String symbol) {
this.symbol = symbol;
}
public double apply(double a, double b) {
throw new UnsupportedOperationException();
}
// Anonymous classes as constants
public static final Operation ADD = new Operation("+") {
@Override
public double apply(double a, double b) {
return a + b;
}
};
public static final Operation SUBTRACT = new Operation("-") {
@Override
public double apply(double a, double b) {
return a - b;
}
};
public static final Operation MULTIPLY = new Operation("*") {
@Override
public double apply(double a, double b) {
return a * b;
}
};
public static final Operation DIVIDE = new Operation("/") {
@Override
public double apply(double a, double b) {
if (b == 0) throw new ArithmeticException("Division by zero");
return a / b;
}
};
@Override
public String toString() {
return symbol;
}
}
// Pattern 4: Fluent builder with inner class
class HttpRequest {
private final String method;
private final String url;
private final String body;
private final java.util.Map<String, String> headers;
private HttpRequest(Builder builder) {
this.method = builder.method;
this.url = builder.url;
this.body = builder.body;
this.headers = new java.util.HashMap<>(builder.headers);
}
// Static inner builder
public static class Builder {
private String method = "GET";
private String url;
private String body = "";
private java.util.Map<String, String> headers = new java.util.HashMap<>();
public Builder url(String url) {
this.url = url;
return this;
}
public Builder get() {
this.method = "GET";
return this;
}
public Builder post(String body) {
this.method = "POST";
this.body = body;
return this;
}
public Builder header(String key, String value) {
this.headers.put(key, value);
return this;
}
public HttpRequest build() {
if (url == null) throw new IllegalStateException("URL required");
return new HttpRequest(this);
}
}
public void send() {
System.out.println(method + " " + url);
headers.forEach((k, v) -> System.out.println(" " + k + ": " + v));
if (!body.isEmpty()) {
System.out.println(" Body: " + body);
}
}
}
// Pattern 5: Composite with member inner class
class FileSystem {
// Member inner class for entries
class Entry {
private String name;
private boolean isDirectory;
private java.util.List<Entry> children;
Entry(String name, boolean isDirectory) {
this.name = name;
this.isDirectory = isDirectory;
this.children = isDirectory ? new java.util.ArrayList<>() : null;
}
public Entry addChild(String name, boolean isDirectory) {
if (!this.isDirectory) {
throw new IllegalStateException("Cannot add child to file");
}
Entry child = new Entry(name, isDirectory); // Uses outer.new Entry()
children.add(child);
return child;
}
public void print(String indent) {
System.out.println(indent + (isDirectory ? "📁 " : "📄 ") + name);
if (children != null) {
for (Entry child : children) {
child.print(indent + " ");
}
}
}
}
private Entry root;
public FileSystem(String rootName) {
this.root = new Entry(rootName, true);
}
public Entry getRoot() {
return root;
}
}
public class InnerClassPatterns {
public static void main(String[] args) {
System.out.println("=== Inner Class Patterns ===\n");
// Pattern 1: Iterator
System.out.println("--- Iterator Pattern ---");
NumberRange range = new NumberRange(1, 5);
for (int num : range) {
System.out.print(num + " ");
}
System.out.println();
// Pattern 2: Callback
System.out.println("\n--- Callback Pattern ---");
TaskRunner runner = new TaskRunner();
runner.runTask("Download", new TaskRunner.TaskCallback() {
@Override
public void onProgress(int percent) {
System.out.println("Progress: " + percent + "%");
}
@Override
public void onComplete(String result) {
System.out.println("Done: " + result);
}
@Override
public void onError(String error) {
System.out.println("Error: " + error);
}
});
// Pattern 3: Operation constants
System.out.println("\n--- Operation Pattern ---");
double a = 10, b = 3;
System.out.println(a + " " + Operation.ADD + " " + b + " = " + Operation.ADD.apply(a, b));
System.out.println(a + " " + Operation.MULTIPLY + " " + b + " = " + Operation.MULTIPLY.apply(a, b));
// Pattern 4: Fluent Builder
System.out.println("\n--- Fluent Builder Pattern ---");
HttpRequest request = new HttpRequest.Builder()
.url("https://api.example.com/users")
.post("{\"name\": \"John\"}")
.header("Content-Type", "application/json")
.header("Authorization", "Bearer token123")
.build();
request.send();
// Pattern 5: Composite
System.out.println("\n--- Composite Pattern ---");
FileSystem fs = new FileSystem("root");
FileSystem.Entry src = fs.getRoot().addChild("src", true);
src.addChild("Main.java", false);
src.addChild("Utils.java", false);
FileSystem.Entry test = fs.getRoot().addChild("test", true);
test.addChild("MainTest.java", false);
fs.getRoot().addChild("README.md", false);
fs.getRoot().print("");
System.out.println("\n=== Pattern Summary ===");
System.out.println("""
1. Iterator: Private inner class hides implementation
2. Callback: Anonymous class for event handling
3. Constants: Anonymous classes for behavior-rich constants
4. Builder: Static nested class for construction
5. Composite: Member inner for tree-like structures
""");
}
}
public static void main(String[] args)
209public class InnerClassPatterns {210 public static void main(String[] args) {211 System.out.println("=== Inner Class Patterns ===\n");212 213 // Pattern 1: Iterator //?testiterator214 System.out.println("--- Iterator Pattern ---");215 NumberRange range = new NumberRange(1, 5);216 for (int num : range) {output=== Inner Class Patterns === --- Iterator Pattern ---this.start ← 1, this.end ← 5
11NumberRange(int start1, int end5) {12 this.start→ 1 = start1;13 this.end→ 5 = end5;14}range ← ⟨NumberRange A⟩
214System.out.println("--- Iterator Pattern ---");215NumberRange range→ ⟨NumberRange A⟩ = new NumberRange(1, 5);216for (int num : range) {@Override public boolean hasNext()
pass 1 of 1125@Override26public boolean hasNext() {27 return current1 <= end5; // Uses outer's end28}All 11 passes — pass 1 is the card above pass current1 1 2 1 3 2 4 2 5 3 6 3 7 4 8 4 9 5 10 5 11 6 return current++;
34 }35 return current1++;36}for (int num : range)
pass 1 of 5215NumberRange range = new NumberRange(1, 5);216for (int num1 : range⟨NumberRange A⟩) {217 System.out.print(num1 + " ");218}output1All 5 passes — pass 1 is the card above pass num1 1 2 2 3 3 4 4 5 5 return current++;
34 }35 return current2++;36}return current++;
34 }35 return current3++;36}return current++;
34 }35 return current4++;36}return current++;
34 }35 return current5++;36}runner ← ⟨TaskRunner B⟩
218}219System.out.println();220221// Pattern 2: Callback //?testcallback222System.out.println("\n--- Callback Pattern ---");223TaskRunner runner→ ⟨TaskRunner B⟩ = new TaskRunner();224runner.runTask("Download", new TaskRunner.TaskCallback() { //?anoncallback225 @Override226 public void onProgress(int percent) {227 System.out.println("Progress: " + percent + "%");228 }229 230 @Override231 public void onComplete(String result) {232 System.out.println("Done: " + result);233 }234 235 @Override236 public void onError(String error) {237 System.out.println("Error: " + error);238 }239});output --- Callback Pattern ---public void runTask(String taskName, TaskCallback callback)
48public void runTask(String taskNameDownload, TaskCallback callback⟨InnerClassPatterns$1 C⟩) {49 System.out.println("Starting task: " + taskNameDownload);outputStarting task: Downloadfor (int i = 0; i <= 100; i += 25)
pass 1 of 551// Simulate progress52for (int i0 = 0; i <= 100; i += 25) {53 callback.onProgress(i0);54}All 5 passes — pass 1 is the card above pass iresult1 0 — 2 25 — 3 50 — 4 75 — 5 100 Task completed successfully! @Override public void onProgress(int percent)
pass 1 of 552 for (int i = 0; i <= 100; i += 25) {53 callback.onProgress(i0);54 }55 56 callback.onComplete("Task completed successfully!");57 }58}5960// Pattern 3: Type-safe constants with behavior //?constantpattern61class Operation { //?operationclass62 private final String symbol;63 64 private Operation(String symbol) {65 this.symbol = symbol;66 }67 68 public double apply(double a, double b) {69 throw new UnsupportedOperationException();70 }71 72 // Anonymous classes as constants //?operationconstants73 public static final Operation ADD = new Operation("+") { //?addop74 @Override75 public double apply(double a, double b) {76 return a + b;77 }78 };79 80 public static final Operation SUBTRACT = new Operation("-") { //?subtractop81 @Override82 public double apply(double a, double b) {83 return a - b;84 }85 };86 87 public static final Operation MULTIPLY = new Operation("*") {88 @Override89 public double apply(double a, double b) {90 return a * b;91 }92 };93 94 public static final Operation DIVIDE = new Operation("/") {95 @Override96 public double apply(double a, double b) {97 if (b == 0) throw new ArithmeticException("Division by zero");98 return a / b;99 }100 };101 102 @Override103 public String toString() {104 return symbol;105 }106}107108// Pattern 4: Fluent builder with inner class //?fluentbuilder109class HttpRequest { //?httprequest110 private final String method;111 private final String url;112 private final String body;113 private final java.util.Map<String, String> headers;114 115 private HttpRequest(Builder builder) {116 this.method = builder.method;117 this.url = builder.url;118 this.body = builder.body;119 this.headers = new java.util.HashMap<>(builder.headers);120 }121 122 // Static inner builder //?staticbuilder123 public static class Builder {124 private String method = "GET";125 private String url;126 private String body = "";127 private java.util.Map<String, String> headers = new java.util.HashMap<>();128 129 public Builder url(String url) {130 this.url = url;131 return this;132 }133 134 public Builder get() {135 this.method = "GET";136 return this;137 }138 139 public Builder post(String body) {140 this.method = "POST";141 this.body = body;142 return this;143 }144 145 public Builder header(String key, String value) {146 this.headers.put(key, value);147 return this;148 }149 150 public HttpRequest build() {151 if (url == null) throw new IllegalStateException("URL required");152 return new HttpRequest(this);153 }154 }155 156 public void send() {157 System.out.println(method + " " + url);158 headers.forEach((k, v) -> System.out.println(" " + k + ": " + v));159 if (!body.isEmpty()) {160 System.out.println(" Body: " + body);161 }162 }163}164165// Pattern 5: Composite with member inner class //?compositepattern166class FileSystem { //?filesystem167 // Member inner class for entries //?entryinner168 class Entry { //?entry169 private String name;170 private boolean isDirectory;171 private java.util.List<Entry> children;172 173 Entry(String name, boolean isDirectory) {174 this.name = name;175 this.isDirectory = isDirectory;176 this.children = isDirectory ? new java.util.ArrayList<>() : null;177 }178 179 public Entry addChild(String name, boolean isDirectory) {180 if (!this.isDirectory) {181 throw new IllegalStateException("Cannot add child to file");182 }183 Entry child = new Entry(name, isDirectory); // Uses outer.new Entry()184 children.add(child);185 return child;186 }187 188 public void print(String indent) {189 System.out.println(indent + (isDirectory ? "📁 " : "📄 ") + name);190 if (children != null) {191 for (Entry child : children) {192 child.print(indent + " ");193 }194 }195 }196 }197 198 private Entry root;199 200 public FileSystem(String rootName) {201 this.root = new Entry(rootName, true);202 }203 204 public Entry getRoot() {205 return root;206 }207}208209public class InnerClassPatterns {210 public static void main(String[] args) {211 System.out.println("=== Inner Class Patterns ===\n");212 213 // Pattern 1: Iterator //?testiterator214 System.out.println("--- Iterator Pattern ---");215 NumberRange range = new NumberRange(1, 5);216 for (int num : range) {217 System.out.print(num + " ");218 }219 System.out.println();220 221 // Pattern 2: Callback //?testcallback222 System.out.println("\n--- Callback Pattern ---");223 TaskRunner runner = new TaskRunner();224 runner.runTask("Download", new TaskRunner.TaskCallback() { //?anoncallback225 @Override226 public void onProgress(int percent0) {227 System.out.println("Progress: " + percent0 + "%");228 }outputProgress: 0%All 5 passes — pass 1 is the card above pass percentiresult1 0 0 — 2 25 25 — 3 50 50 — 4 75 75 — 5 100 100 Task completed successfully! @Override public void onComplete(String result)
56 callback.onComplete("Task completed successfully!");57 }58}5960// Pattern 3: Type-safe constants with behavior //?constantpattern61class Operation { //?operationclass62 private final String symbol;63 64 private Operation(String symbol) {65 this.symbol = symbol;66 }67 68 public double apply(double a, double b) {69 throw new UnsupportedOperationException();70 }71 72 // Anonymous classes as constants //?operationconstants73 public static final Operation ADD = new Operation("+") { //?addop74 @Override75 public double apply(double a, double b) {76 return a + b;77 }78 };79 80 public static final Operation SUBTRACT = new Operation("-") { //?subtractop81 @Override82 public double apply(double a, double b) {83 return a - b;84 }85 };86 87 public static final Operation MULTIPLY = new Operation("*") {88 @Override89 public double apply(double a, double b) {90 return a * b;91 }92 };93 94 public static final Operation DIVIDE = new Operation("/") {95 @Override96 public double apply(double a, double b) {97 if (b == 0) throw new ArithmeticException("Division by zero");98 return a / b;99 }100 };101 102 @Override103 public String toString() {104 return symbol;105 }106}107108// Pattern 4: Fluent builder with inner class //?fluentbuilder109class HttpRequest { //?httprequest110 private final String method;111 private final String url;112 private final String body;113 private final java.util.Map<String, String> headers;114 115 private HttpRequest(Builder builder) {116 this.method = builder.method;117 this.url = builder.url;118 this.body = builder.body;119 this.headers = new java.util.HashMap<>(builder.headers);120 }121 122 // Static inner builder //?staticbuilder123 public static class Builder {124 private String method = "GET";125 private String url;126 private String body = "";127 private java.util.Map<String, String> headers = new java.util.HashMap<>();128 129 public Builder url(String url) {130 this.url = url;131 return this;132 }133 134 public Builder get() {135 this.method = "GET";136 return this;137 }138 139 public Builder post(String body) {140 this.method = "POST";141 this.body = body;142 return this;143 }144 145 public Builder header(String key, String value) {146 this.headers.put(key, value);147 return this;148 }149 150 public HttpRequest build() {151 if (url == null) throw new IllegalStateException("URL required");152 return new HttpRequest(this);153 }154 }155 156 public void send() {157 System.out.println(method + " " + url);158 headers.forEach((k, v) -> System.out.println(" " + k + ": " + v));159 if (!body.isEmpty()) {160 System.out.println(" Body: " + body);161 }162 }163}164165// Pattern 5: Composite with member inner class //?compositepattern166class FileSystem { //?filesystem167 // Member inner class for entries //?entryinner168 class Entry { //?entry169 private String name;170 private boolean isDirectory;171 private java.util.List<Entry> children;172 173 Entry(String name, boolean isDirectory) {174 this.name = name;175 this.isDirectory = isDirectory;176 this.children = isDirectory ? new java.util.ArrayList<>() : null;177 }178 179 public Entry addChild(String name, boolean isDirectory) {180 if (!this.isDirectory) {181 throw new IllegalStateException("Cannot add child to file");182 }183 Entry child = new Entry(name, isDirectory); // Uses outer.new Entry()184 children.add(child);185 return child;186 }187 188 public void print(String indent) {189 System.out.println(indent + (isDirectory ? "📁 " : "📄 ") + name);190 if (children != null) {191 for (Entry child : children) {192 child.print(indent + " ");193 }194 }195 }196 }197 198 private Entry root;199 200 public FileSystem(String rootName) {201 this.root = new Entry(rootName, true);202 }203 204 public Entry getRoot() {205 return root;206 }207}208209public class InnerClassPatterns {210 public static void main(String[] args) {211 System.out.println("=== Inner Class Patterns ===\n");212 213 // Pattern 1: Iterator //?testiterator214 System.out.println("--- Iterator Pattern ---");215 NumberRange range = new NumberRange(1, 5);216 for (int num : range) {217 System.out.print(num + " ");218 }219 System.out.println();220 221 // Pattern 2: Callback //?testcallback222 System.out.println("\n--- Callback Pattern ---");223 TaskRunner runner = new TaskRunner();224 runner.runTask("Download", new TaskRunner.TaskCallback() { //?anoncallback225 @Override226 public void onProgress(int percent) {227 System.out.println("Progress: " + percent + "%");228 }229 230 @Override231 public void onComplete(String resultTask completed successfully!) {232 System.out.println("Done: " + resultTask completed successfully!);233 }234 235 @Override236 public void onError(String error) {237 System.out.println("Error: " + error);238 }239 });outputDone: Task completed successfully!b ← 3.0
241// Pattern 3: Operation constants //?testoperation242System.out.println("\n--- Operation Pattern ---");243double a = 10, b→ 3.0 = 3;244System.out.println(a10.0 + " " + Operation.ADD + " " + b3.0 + " = " + Operation.ADD.apply(a, b));245System.out.println(a + " " + Operation.MULTIPLY + " " + b + " = " + Operation.MULTIPLY.apply(a, b));output --- Operation Pattern ---this.symbol ← +
pass 1 of 464private Operation(String symbol+) {65 this.symbol→ + = symbol+;66}All 4 passes — pass 1 is the card above pass symbolabthis.symbol1 + — — + 2 - — — - 3 * — — * 4 / 10.0 3.0 / @Override public double apply(double a, double b)
73public static final Operation ADD = new Operation("+") { //?addop74 @Override75 public double apply(double a10.0, double b3.0) {76 return a10.0 + b3.0;77 }System.out.println(a + " " + Operation.ADD + " " + b + " = " + Operati…
243double a = 10, b = 3;244System.out.println(a10.0 + " " + Operation.ADD + " " + b3.0 + " = " + Operation.ADD.apply(a, b));245System.out.println(a10.0 + " " + Operation.MULTIPLY + " " + b3.0 + " = " + Operation.MULTIPLY.apply(a, b));output10.0 + 3.0 = 13.0@Override public double apply(double a, double b)
87public static final Operation MULTIPLY = new Operation("*") {88 @Override89 public double apply(double a10.0, double b3.0) {90 return a10.0 * b3.0;91 }System.out.println(a + " " + Operation.MULTIPLY + " " + b + " = " + Op…
244System.out.println(a + " " + Operation.ADD + " " + b + " = " + Operation.ADD.apply(a, b));245System.out.println(a10.0 + " " + Operation.MULTIPLY + " " + b3.0 + " = " + Operation.MULTIPLY.apply(a, b));246247// Pattern 4: Fluent Builder //?testbuilder248System.out.println("\n--- Fluent Builder Pattern ---");249HttpRequest request = new HttpRequest.Builder()250 .url("https://api.example.com/users")251 .post("{\"name\": \"John\"}")252 .header("Content-Type", "application/json")253 .header("Authorization", "Bearer token123")254 .build();255request.send();output10.0 * 3.0 = 30.0 --- Fluent Builder Pattern ---this.url ← https://api.example.com/users
129public Builder url(String urlhttps://api.example.com/users) {130 this.url→ https://api.example.com/users = urlhttps://api.example.com/users;131 return this;132}this.method ← POST, this.body ← {"name": "John"}
139public Builder post(String body{"name": "John"}) {140 this.method→ POST = "POST";141 this.body→ {"name": "John"} = body{"name": "John"};142 return this;143}this.headers ← {Content-Type=application/json}
pass 1 of 2145public Builder header(String keyContent-Type, String valueapplication/json) {146 this.headers→ {Content-Type=application/json}.put(keyContent-Type, valueapplication/json);147 return this;148}this.headers ← {Authorization=Bearer token123, Content-Type=application/json}
pass 2 of 2145public Builder header(String keyAuthorization, String valueBearer token123) {146 this.headers→ {Authorization=Bearer token123, Content-Type=application/json}.put(keyAuthorization, valueBearer token123);147 return this;148}this.method ← POST, this.url ← https://api.example.com/users, this.body ← {"name": "John"}
115private HttpRequest(Builder builder⟨HttpRequest$Builder D⟩) {116 this.method→ POST = builder.methodPOST;117 this.url→ https://api.example.com/users = builder.urlhttps://api.example.com/users;118 this.body→ {"name": "John"} = builder.body{"name": "John"};119 this.headers→ {Authorization=Bearer token123, Content-Type=application/json} = new java.util.HashMap<>(builder.headers);120}request ← ⟨HttpRequest E⟩
248System.out.println("\n--- Fluent Builder Pattern ---");249HttpRequest request→ ⟨HttpRequest E⟩ = new HttpRequest.Builder()250 .url("https://api.example.com/users")251 .post("{\"name\": \"John\"}")252 .header("Content-Type", "application/json")253 .header("Authorization", "Bearer token123")254 .build();255request.send();public void send()
156public void send() {157 System.out.println(methodPOST + " " + urlhttps://api.example.com/users);158 headers.forEach((k, v) -> System.out.println(" " + k + ": " + v));159 if (!body.isEmpty()) {outputPOST https://api.example.com/usersif (!body.isEmpty())
158headers.forEach((k, v) -> System.out.println(" " + k + ": " + v));159if (!body.isEmpty()) {160 System.out.println(" Body: " + body{"name": "John"});161}output Body: {"name": "John"}request.send();
254 .build();255request.send();256257// Pattern 5: Composite //?testcomposite258System.out.println("\n--- Composite Pattern ---");259FileSystem fs = new FileSystem("root");260FileSystem.Entry src = fs.getRoot().addChild("src", true);output --- Composite Pattern ---public FileSystem(String rootName)
200public FileSystem(String rootNameroot) {201 this.root = new Entry(rootName, true);202}this.name ← root, this.isDirectory ← true, this.children ← []
pass 1 of 7173Entry(String nameroot, boolean isDirectorytrue) {174 this.name→ root = nameroot;175 this.isDirectory→ true = isDirectorytrue;176 this.children→ [] = isDirectorytrue ? new java.util.ArrayList<>() : null;177}All 7 passes — pass 1 is the card above pass nameisDirectorythis.namethis.isDirectorythis.children1 root true root true [] 2 src true src true [] 3 Main.java false Main.java false null 4 Utils.java false Utils.java false null 5 test true test true [] 6 MainTest.java false MainTest.java false null 7 README.md false README.md false null this.root ← ⟨FileSystem$Entry F⟩
200public FileSystem(String rootName) {201 this.root→ ⟨FileSystem$Entry F⟩ = new Entry(rootName, true);202}fs ← ⟨FileSystem G⟩
258System.out.println("\n--- Composite Pattern ---");259FileSystem fs→ ⟨FileSystem G⟩ = new FileSystem("root");260FileSystem.Entry src = fs.getRoot().addChild("src", true);261src.addChild("Main.java", false);public Entry getRoot()
pass 1 of 4204public Entry getRoot() {205 return root⟨FileSystem$Entry F⟩;206}public Entry addChild(String name, boolean isDirectory)
pass 1 of 6179public Entry addChild(String namesrc, boolean isDirectorytrue) {180 if (!this.isDirectory) {181 throw new IllegalStateException("Cannot add child to file");182 }183 Entry child = new Entry(name, isDirectory); // Uses outer.new Entry()184 children.add(child);All 6 passes — pass 1 is the card above pass nameisDirectory1 src true 2 Main.java false 3 Utils.java false 4 test true 5 MainTest.java false 6 README.md false child ← ⟨FileSystem$Entry H⟩
182 }183 Entry child→ ⟨FileSystem$Entry H⟩ = new Entry(name, isDirectory); // Uses outer.new Entry()184 children.add(child⟨FileSystem$Entry H⟩);185 return child⟨FileSystem$Entry H⟩;186}src ← ⟨FileSystem$Entry H⟩
259FileSystem fs = new FileSystem("root");260FileSystem.Entry src→ ⟨FileSystem$Entry H⟩ = fs.getRoot().addChild("src", true);261src.addChild("Main.java", false);262src.addChild("Utils.java", false);child ← ⟨FileSystem$Entry I⟩
182 }183 Entry child→ ⟨FileSystem$Entry I⟩ = new Entry(name, isDirectory); // Uses outer.new Entry()184 children.add(child⟨FileSystem$Entry I⟩);185 return child⟨FileSystem$Entry I⟩;186}src.addChild("Main.java", false);
260FileSystem.Entry src = fs.getRoot().addChild("src", true);261src.addChild("Main.java", false);262src.addChild("Utils.java", false);263FileSystem.Entry test = fs.getRoot().addChild("test", true);child ← ⟨FileSystem$Entry J⟩
182 }183 Entry child→ ⟨FileSystem$Entry J⟩ = new Entry(name, isDirectory); // Uses outer.new Entry()184 children.add(child⟨FileSystem$Entry J⟩);185 return child⟨FileSystem$Entry J⟩;186}src.addChild("Utils.java", false);
261src.addChild("Main.java", false);262src.addChild("Utils.java", false);263FileSystem.Entry test = fs.getRoot().addChild("test", true);264test.addChild("MainTest.java", false);child ← ⟨FileSystem$Entry K⟩
182 }183 Entry child→ ⟨FileSystem$Entry K⟩ = new Entry(name, isDirectory); // Uses outer.new Entry()184 children.add(child⟨FileSystem$Entry K⟩);185 return child⟨FileSystem$Entry K⟩;186}test ← ⟨FileSystem$Entry K⟩
262src.addChild("Utils.java", false);263FileSystem.Entry test→ ⟨FileSystem$Entry K⟩ = fs.getRoot().addChild("test", true);264test.addChild("MainTest.java", false);265fs.getRoot().addChild("README.md", false);child ← ⟨FileSystem$Entry L⟩
182 }183 Entry child→ ⟨FileSystem$Entry L⟩ = new Entry(name, isDirectory); // Uses outer.new Entry()184 children.add(child⟨FileSystem$Entry L⟩);185 return child⟨FileSystem$Entry L⟩;186}test.addChild("MainTest.java", false);
263FileSystem.Entry test = fs.getRoot().addChild("test", true);264test.addChild("MainTest.java", false);265fs.getRoot().addChild("README.md", false);child ← ⟨FileSystem$Entry M⟩
182 }183 Entry child→ ⟨FileSystem$Entry M⟩ = new Entry(name, isDirectory); // Uses outer.new Entry()184 children.add(child⟨FileSystem$Entry M⟩);185 return child⟨FileSystem$Entry M⟩;186}fs.getRoot().addChild("README.md", false);
264test.addChild("MainTest.java", false);265fs.getRoot().addChild("README.md", false);266267fs.getRoot().print("");public void print(String indent)
pass 1 of 7188public void print(String indent(empty)) {189 System.out.println(indent(empty) + (isDirectorytrue ? "📁 " : "📄 ") + nameroot);190 if (children != null) {output📁 rootAll 7 passes — pass 1 is the card above pass isDirectorynameindent1 true root (empty) 2 true src 3 false Main.java 4 false Utils.java → (empty) 5 true test 6 false MainTest.java → (empty) 7 false README.md if (children != null)
pass 1 of 3189System.out.println(indent + (isDirectory ? "📁 " : "📄 ") + name);190if (children⟨FileSystem$Entry[] H⟩, ⟨FileSystem$Entry K⟩, ⟨FileSystem$Entry M⟩] != null) {191 for (Entry child : children) {All 3 passes — pass 1 is the card above pass children1 ⟨FileSystem$Entry[] H⟩, ⟨FileSystem$Entry K⟩, ⟨FileSystem$Entry M⟩] 2 ⟨FileSystem$Entry[] I⟩, ⟨FileSystem$Entry J⟩] 3 ⟨FileSystem$Entry[] L⟩] for (Entry child : children)
pass 1 of 6190if (children != null) {191 for (Entry child⟨FileSystem$Entry H⟩ : children⟨FileSystem$Entry[] H⟩, ⟨FileSystem$Entry K⟩, ⟨FileSystem$Entry M⟩]) {192 child.print(indent(empty) + " ");193 }All 6 passes — pass 1 is the card above pass childchildrenindent1 ⟨FileSystem$Entry H⟩ ⟨FileSystem$Entry[] H⟩, ⟨FileSystem$Entry K⟩, ⟨FileSystem$Entry M⟩] (empty) 2 ⟨FileSystem$Entry I⟩ ⟨FileSystem$Entry[] I⟩, ⟨FileSystem$Entry J⟩] 3 ⟨FileSystem$Entry J⟩ ⟨FileSystem$Entry[] I⟩, ⟨FileSystem$Entry J⟩] 4 ⟨FileSystem$Entry K⟩ ⟨FileSystem$Entry[] H⟩, ⟨FileSystem$Entry K⟩, ⟨FileSystem$Entry M⟩] (empty) 5 ⟨FileSystem$Entry L⟩ ⟨FileSystem$Entry[] L⟩] 6 ⟨FileSystem$Entry M⟩ ⟨FileSystem$Entry[] H⟩, ⟨FileSystem$Entry K⟩, ⟨FileSystem$Entry M⟩] (empty) fs.getRoot().print("");
267 fs.getRoot().print("");268 269 System.out.println("\n=== Pattern Summary ===");270 System.out.println("""271 1. Iterator: Private inner class hides implementation272 2. Callback: Anonymous class for event handling273 3. Constants: Anonymous classes for behavior-rich constants274 4. Builder: Static nested class for construction275 5. Composite: Member inner for tree-like structures276 """);277}output === Pattern Summary === 1. Iterator: Private inner class hides implementation 2. Callback: Anonymous class for event handling 3. Constants: Anonymous classes for behavior-rich constants 4. Builder: Static nested class for construction 5. Composite: Member inner for tree-like structures
Iterators, builders, event handlers - all classic inner class uses.
Exercise: Practical.java
Build a data structure with inner helper classes