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.

MemberInner.java
Replay: real traced execution (multi-file project)
// 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
            """);
    }
}
  1. 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 ===
  2. this.name ← MyOuter

    7OuterClass(String nameMyOuter) {8    this.name→ MyOuter = nameMyOuter;9}
  3. 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"); //?innercreation
  4. this.innerName ← MyInner

    15InnerClass(String innerNameMyInner) {16    this.innerName→ MyInner = innerNameMyInner;17}
  5. inner ← ⟨OuterClass$InnerClass B⟩

    99// Create inner class instance //?createinner100OuterClass.InnerClass inner→ ⟨OuterClass$InnerClass B⟩ = outer.new InnerClass("MyInner"); //?innercreation101102inner.display();
  6. 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: 0
  7. inner.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 ---
  8. public int getCount()

    pass 1 of 2
    42public int getCount() {43    return count0;44}
  9. 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: 0
  10. count ← 1

    pass 1 of 2
    26void incrementCount() { //?modifyouter27    count→ 1++;  // Can modify outer's fields28}
  11. inner.incrementCount();

    105System.out.println("Count before: " + outer.getCount());106inner.incrementCount();107inner.incrementCount();108System.out.println("Count after: " + outer.getCount());
  12. count ← 2

    pass 2 of 2
    26void incrementCount() { //?modifyouter27    count→ 2++;  // Can modify outer's fields28}
  13. inner.incrementCount();

    106inner.incrementCount();107inner.incrementCount();108System.out.println("Count after: " + outer.getCount());
  14. public int getCount()

    pass 2 of 2
    42public int getCount() {43    return count2;44}
  15. 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 ---
  16. void showOuterReference()

    30// Access outer class reference //?outerreference31void showOuterReference() {32    System.out.println("Outer this: " + OuterClass.this); //?outerthis33}
    outputOuter this: ⟨OuterClass A⟩
  17. 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 ===
  18. public void add(T item)

    pass 1 of 3
    63public void add(T itemApple) { //?addmethod64    Node newNode = new Node(item);65    if (head == null) {
    All 3 passes — pass 1 is the card above
    passitem
    1Apple
    2Banana
    3Cherry
  19. this.data ← Apple, this.next ← null

    pass 1 of 3
    57Node(T dataApple) {58    this.data→ Apple = dataApple;59    this.next→ null = null;60}
    All 3 passes — pass 1 is the card above
    passdatathis.datathis.next
    1AppleApplenull
    2BananaBanananull
    3CherryCherrynull
  20. newNode ← ⟨SimpleList$Node D⟩

    63public void add(T item) { //?addmethod64    Node newNode→ ⟨SimpleList$Node D⟩ = new Node(item);65    if (head == null) {
  21. head ← ⟨SimpleList$Node D⟩

    64Node newNode = new Node(item);65if (headnull == null) {66    head→ ⟨SimpleList$Node D⟩ = newNode⟨SimpleList$Node D⟩;67} else {
  22. size ← 1

    73    }74    size→ 1++;  // Inner class indirectly affects outer75}
  23. list.add("Apple");

    114SimpleList<String> list = new SimpleList<>();115list.add("Apple");116list.add("Banana");117list.add("Cherry");
  24. newNode ← ⟨SimpleList$Node E⟩

    63public void add(T item) { //?addmethod64    Node newNode→ ⟨SimpleList$Node E⟩ = new Node(item);65    if (head == null) {
  25. current ← ⟨SimpleList$Node D⟩, current.next ← ⟨SimpleList$Node E⟩

    pass 1 of 2
    66    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}
  26. size ← 2

    73    }74    size→ 2++;  // Inner class indirectly affects outer75}
  27. list.add("Banana");

    115list.add("Apple");116list.add("Banana");117list.add("Cherry");
  28. newNode ← ⟨SimpleList$Node F⟩

    63public void add(T item) { //?addmethod64    Node newNode→ ⟨SimpleList$Node F⟩ = new Node(item);65    if (head == null) {
  29. current ← ⟨SimpleList$Node D⟩

    pass 2 of 2
    66    head = newNode;67} else {68    Node current→ ⟨SimpleList$Node D⟩ = head;69    while (current.next != null) {
  30. 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}
  31. 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⟩current
  32. size ← 3

    73    }74    size→ 3++;  // Inner class indirectly affects outer75}
  33. list.add("Cherry");

    116list.add("Banana");117list.add("Cherry");118119System.out.println("Size: " + list.size());120list.printAll();
  34. public int size()

    87public int size() {88    return size3;89}
  35. System.out.println("Size: " + list.size());

    119System.out.println("Size: " + list.size());120list.printAll();121// Node class is hidden - cannot access from here
    outputSize: 3
  36. current ← ⟨SimpleList$Node D⟩

    77public void printAll() {78    Node current→ ⟨SimpleList$Node D⟩ = head;79    while (current != null) {
  37. next ← ⟨SimpleList$Node E⟩, current ← ⟨SimpleList$Node E⟩

    pass 1 of 3
    78Node 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
    passcurrent.datacurrent.nextnextcurrent
    1Apple⟨SimpleList$Node E⟩⟨SimpleList$Node E⟩⟨SimpleList$Node D⟩ ⟨SimpleList$Node E⟩
    2Banana⟨SimpleList$Node F⟩⟨SimpleList$Node F⟩⟨SimpleList$Node E⟩ ⟨SimpleList$Node F⟩
    3Cherrynullnull⟨SimpleList$Node F⟩ null
  38. System.out.println("null");

    83    }84    System.out.println("null");85}
    outputnull
  39. list.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.

inner class Class defined inside another. Has implicit reference to outer instance.

Static nested class

A nested class that doesn't need an outer instance.

StaticNested.java
Replay: real traced execution (multi-file project)
// 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
            """);
    }
}
  1. 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 ===
  2. 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}
  3. 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.53975
  4. static double square(double n)

    18static double square(double n7.0) {19    return n7.0 * n;20}
  5. 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.0
  6. static double cube(double n)

    22static double cube(double n3.0) {23    return n3.0 * n * n;24}
  7. 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.0
  8. this.precision ← 4, this.useRadians ← true

    42Config(int precision4, boolean useRadianstrue) {43    this.precision→ 4 = precision4;44    this.useRadians→ true = useRadianstrue;45}
  9. 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}
  10. this.precision ← 2, this.useRadians ← false

    37Config() {38    this.precision→ 2 = 2;39    this.useRadians→ false = false;40}
  11. 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 ===
  12. this.size ← large

    pass 1 of 3
    97public Builder(String sizelarge) { //?builderconstructor98    this.size→ large = sizelarge;99}
    All 3 passes — pass 1 is the card above
    passsizecrustthis.sizethis.crustthis.pepperonithis.mushroomsthis.onionsthis.cheese
    1largethinlargethintruetrue
    2mediummediumtruetruefalse
    3smallsmall
  13. this.crust ← thin

    101public Builder crust(String crustthin) { //?crustmethod102    this.crust→ thin = crustthin;103    return this;  // Return this for chaining104}
  14. this.pepperoni ← true

    pass 1 of 2
    106public Builder pepperoni() { //?toppingmethod107    this.pepperoni→ true = true;108    return this;109}
  15. this.mushrooms ← true

    111public Builder mushrooms() {112    this.mushrooms→ true = true;113    return this;114}
  16. this.size ← large, this.crust ← thin, this.cheese ← true, this.pepperoni ← true

    pass 1 of 3
    75// 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
    passbuilderbuilder.sizebuilder.crustbuilder.cheesebuilder.pepperonibuilder.mushroomsbuilder.onionsthis.sizethis.crustthis.cheesethis.pepperonithis.mushroomsthis.onions
    1⟨Pizza$Builder A⟩largethintruetruetruefalselargethintruetruetruefalse
    2⟨Pizza$Builder B⟩mediumregularfalsetruefalsetruemediumregularfalsetruefalsetrue
    3⟨Pizza$Builder C⟩smallregulartruefalsefalsefalsesmallregulartruefalsefalsefalse
  17. 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, mushrooms
  18. this.pepperoni ← true

    pass 2 of 2
    106public Builder pepperoni() { //?toppingmethod107    this.pepperoni→ true = true;108    return this;109}
  19. this.onions ← true

    116public Builder onions() {117    this.onions→ true = true;118    return this;119}
  20. this.cheese ← false

    121public Builder noCheese() {122    this.cheese→ false = false;123    return this;124}
  21. 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, onions
  22. pizza3 ← 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.

static nested class Nested class with `static`. Independent of outer instance.

Local class

A class defined inside a method.

maxAllowed
LocalClass.java
Replay: real traced execution (multi-file project)
// 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)
            """);
    }
}
  1. 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 ---
  2. this.processorName ← MainProcessor

    9DataProcessor(String nameMainProcessor) {10    this.processorName→ MainProcessor = nameMainProcessor;11}
  3. 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");
  4. 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());
  5. String getProcessorInfo()

    27// Can access outer class members //?accessouter28String getProcessorInfo() {29    return "Processor: " + processorNameMainProcessor;30}
  6. result ← []

    38DataTransformer transformer = new DataTransformer();39System.out.println(transformer.getProcessorInfo());4041List<String> result→ [] = new ArrayList<>();42for (String item : data) {
    outputProcessor: MainProcessor
  7. for (String item : data)

    pass 1 of 3
    41List<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
    passitem
    1apple
    2banana
    3cherry
  8. count ← 1

    pass 1 of 3
    20// 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
    passitemcount
    1apple0 1
    2banana1 2
    3cherry2 3
  9. result.add(transformer.transform(item));

    42for (String item : data) {43    result.add(transformer.transform(itemapple));44}
  10. result.add(transformer.transform(item));

    42for (String item : data) {43    result.add(transformer.transform(itembanana));44}
  11. result.add(transformer.transform(item));

    42for (String item : data) {43    result.add(transformer.transform(itemcherry));44}
  12. System.out.println("Transformed " + transformer.getCount() + " items")…

    46System.out.println("Transformed " + transformer.getCount() + " items");47return result;
  13. int getCount()

    32int getCount() {33    return count3;34}
  14. return result;

    46System.out.println("Transformed " + transformer.getCount() + " items");47return result[ITEM: APPLE (#1), ITEM: BANANA (#2), ITEM: CHERRY (#3)];
    outputTransformed 3 items
  15. processed ← [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:
  16. for (String item : processed)

    pass 1 of 3
    123System.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
    passitem
    1ITEM: APPLE (#1)
    2ITEM: BANANA (#2)
    3ITEM: CHERRY (#3)
  17. 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 ---
  18. public boolean validateAll(List<Integer> numbers, int minValue, int ma…

    pass 1 of 2
    52// 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());
  19. String getRange()

    pass 1 of 2
    62String getRange() {63    return "[" + minValue1 + ", " + maxValue30 + "]";64}
  20. System.out.println("Validating range: " + validator.getRange());

    67RangeValidator validator = new RangeValidator();68System.out.println("Validating range: " + validator.getRange());
    outputValidating range: [1, 30]
  21. for (int num : numbers)

    pass 1 of 8
    70for (int num5 : numbers[5, 10, 15, 20, 25]) {71    if (!validator.isValid(num)) {
    All 8 passes — pass 1 is the card above
    passnumnumbers
    15[5, 10, 15, 20, 25]
    210[5, 10, 15, 20, 25]
    315[5, 10, 15, 20, 25]
    420[5, 10, 15, 20, 25]
    525[5, 10, 15, 20, 25]
    65[5, 10, 50, 20]
    710[5, 10, 50, 20]
    850[5, 10, 50, 20]
  22. boolean isValid(int num)

    pass 1 of 8
    57// 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
    passnum
    15
    210
    315
    420
    525
    65
    710
    850
  23. return true;

    75    }76    return true;77}
  24. 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: true
  25. public boolean validateAll(List<Integer> numbers, int minValue, int ma…

    pass 2 of 2
    52// 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());
  26. String getRange()

    pass 2 of 2
    62String getRange() {63    return "[" + minValue1 + ", " + maxValue30 + "]";64}
  27. System.out.println("Validating range: " + validator.getRange());

    67RangeValidator validator = new RangeValidator();68System.out.println("Validating range: " + validator.getRange());
    outputValidating range: [1, 30]
  28. if (!validator.isValid(num))

    70for (int num : numbers) {71    if (!validator.isValid(num50)) {72        System.out.println("Invalid: " + num50);73        return false;74    }
    outputInvalid: 50
  29. valid ← 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 ---
  30. public void simulateEvents(List<String> events)

    87public void simulateEvents(List<String> events[START, PROCESS, COMPLETE]) {88    // Local class implementing interface //?localimpl
  31. for (String event : events)

    pass 1 of 3
    105for (String eventSTART : events[START, PROCESS, COMPLETE]) {106    handler.handle(eventSTART);107}
    All 3 passes — pass 1 is the card above
    passevent
    1START
    2PROCESS
    3COMPLETE
  32. eventCount ← 1

    pass 1 of 3
    92@Override93public void handle(String eventSTART) {94    eventCount→ 1++;95    System.out.println("[Event " + eventCount1 + "] " + eventSTART);96}
    output[Event 1] START
    All 3 passes — pass 1 is the card above
    passeventeventCount
    1START0 1
    2PROCESS1 2
    3COMPLETE2 3
  33. handler.handle(event);

    105for (String event : events) {106    handler.handle(eventSTART);107}
  34. handler.handle(event);

    105for (String event : events) {106    handler.handle(eventPROCESS);107}
  35. handler.handle(event);

    105for (String event : events) {106    handler.handle(eventCOMPLETE);107}
  36. System.out.println("Total events handled: " + handler.getEventCount())…

    109    System.out.println("Total events handled: " + handler.getEventCount());110}
  37. public int getEventCount()

    98public int getEventCount() {99    return eventCount3;100}
  38. System.out.println("Total events handled: " + handler.getEventCount())…

    109    System.out.println("Total events handled: " + handler.getEventCount());110}
    outputTotal events handled: 3
  39. simulator.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)
  1. 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 ---
  2. this.processorName ← MainProcessor

    9DataProcessor(String nameMainProcessor) {10    this.processorName→ MainProcessor = nameMainProcessor;11}
  3. 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");
  4. 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());
  5. String getProcessorInfo()

    27// Can access outer class members28String getProcessorInfo() {29    return "Processor: " + processorNameMainProcessor;30}
  6. result ← []

    38DataTransformer transformer = new DataTransformer();39System.out.println(transformer.getProcessorInfo());4041List<String> result→ [] = new ArrayList<>();42for (String item : data) {
    outputProcessor: MainProcessor
  7. for (String item : data)

    pass 1 of 3
    41List<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
    passitem
    1apple
    2banana
    3cherry
  8. count ← 1

    pass 1 of 3
    20// 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
    passitemcount
    1apple0 1
    2banana1 2
    3cherry2 3
  9. result.add(transformer.transform(item));

    42for (String item : data) {43    result.add(transformer.transform(itemapple));44}
  10. result.add(transformer.transform(item));

    42for (String item : data) {43    result.add(transformer.transform(itembanana));44}
  11. result.add(transformer.transform(item));

    42for (String item : data) {43    result.add(transformer.transform(itemcherry));44}
  12. System.out.println("Transformed " + transformer.getCount() + " items")…

    46System.out.println("Transformed " + transformer.getCount() + " items");47return result;
  13. int getCount()

    32int getCount() {33    return count3;34}
  14. return result;

    46System.out.println("Transformed " + transformer.getCount() + " items");47return result[ITEM: APPLE (#1), ITEM: BANANA (#2), ITEM: CHERRY (#3)];
    outputTransformed 3 items
  15. processed ← [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:
  16. for (String item : processed)

    pass 1 of 3
    123System.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
    passitem
    1ITEM: APPLE (#1)
    2ITEM: BANANA (#2)
    3ITEM: CHERRY (#3)
  17. 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 ---
  18. public boolean validateAll(List<Integer> numbers, int minValue, int ma…

    pass 1 of 2
    52// 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());
  19. String getRange()

    pass 1 of 2
    62String getRange() {63    return "[" + minValue1 + ", " + maxValue18 + "]";64}
  20. System.out.println("Validating range: " + validator.getRange());

    67RangeValidator validator = new RangeValidator();68System.out.println("Validating range: " + validator.getRange());
    outputValidating range: [1, 18]
  21. for (int num : numbers)

    pass 1 of 7
    70for (int num5 : numbers[5, 10, 15, 20, 25]) {71    if (!validator.isValid(num)) {
    All 7 passes — pass 1 is the card above
    passnumnumbers
    15[5, 10, 15, 20, 25]
    210[5, 10, 15, 20, 25]
    315[5, 10, 15, 20, 25]
    420[5, 10, 15, 20, 25]
    55[5, 10, 50, 20]
    610[5, 10, 50, 20]
    750[5, 10, 50, 20]
  22. boolean isValid(int num)

    pass 1 of 7
    57// 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
    passnum
    15
    210
    315
    420
    55
    610
    750
  23. if (!validator.isValid(num))

    pass 1 of 2
    70for (int num : numbers) {71    if (!validator.isValid(num20)) {72        System.out.println("Invalid: " + num20);73        return false;74    }
    outputInvalid: 20
  24. valid ← 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: false
  25. public boolean validateAll(List<Integer> numbers, int minValue, int ma…

    pass 2 of 2
    52// 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());
  26. String getRange()

    pass 2 of 2
    62String getRange() {63    return "[" + minValue1 + ", " + maxValue18 + "]";64}
  27. System.out.println("Validating range: " + validator.getRange());

    67RangeValidator validator = new RangeValidator();68System.out.println("Validating range: " + validator.getRange());
    outputValidating range: [1, 18]
  28. if (!validator.isValid(num))

    pass 2 of 2
    70for (int num : numbers) {71    if (!validator.isValid(num50)) {72        System.out.println("Invalid: " + num50);73        return false;74    }
    outputInvalid: 50
  29. valid ← 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 ---
  30. public void simulateEvents(List<String> events)

    87public void simulateEvents(List<String> events[START, PROCESS, COMPLETE]) {88    // Local class implementing interface
  31. for (String event : events)

    pass 1 of 3
    105for (String eventSTART : events[START, PROCESS, COMPLETE]) {106    handler.handle(eventSTART);107}
    All 3 passes — pass 1 is the card above
    passevent
    1START
    2PROCESS
    3COMPLETE
  32. eventCount ← 1

    pass 1 of 3
    92@Override93public void handle(String eventSTART) {94    eventCount→ 1++;95    System.out.println("[Event " + eventCount1 + "] " + eventSTART);96}
    output[Event 1] START
    All 3 passes — pass 1 is the card above
    passeventeventCount
    1START0 1
    2PROCESS1 2
    3COMPLETE2 3
  33. handler.handle(event);

    105for (String event : events) {106    handler.handle(eventSTART);107}
  34. handler.handle(event);

    105for (String event : events) {106    handler.handle(eventPROCESS);107}
  35. handler.handle(event);

    105for (String event : events) {106    handler.handle(eventCOMPLETE);107}
  36. System.out.println("Total events handled: " + handler.getEventCount())…

    109    System.out.println("Total events handled: " + handler.getEventCount());110}
  37. public int getEventCount()

    98public int getEventCount() {99    return eventCount3;100}
  38. System.out.println("Total events handled: " + handler.getEventCount())…

    109    System.out.println("Total events handled: " + handler.getEventCount());110}
    outputTotal events handled: 3
  39. simulator.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.

times
AnonymousClass.java
Replay: real traced execution (multi-file project)
// 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)
            """);
    }
}
  1. 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 ---
  2. @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?
  3. formalGreeting.greet("Sir");

    86formalGreeting.greet("Sir");87casualGreeting.greet("buddy");
  4. @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?
  5. 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 method
    output
    --- Extending Abstract Class ---
  6. @Override void makeSound()

    91Animal dog = new Animal() { //?doganimous92    @Override93    void makeSound() {94        System.out.println("Woof woof!");95    }
    outputWoof woof!
  7. dog.makeSound();

    110dog.makeSound();111dog.sleep();  // Inherited method
  8. void sleep()

    15void sleep() {16    System.out.println("Zzz...");17}
    outputZzz...
  9. dog.sleep(); // Inherited method

    110dog.makeSound();111dog.sleep();  // Inherited method112113cat.makeSound();114// cat.purr();  // Cannot call - Animal doesn't have purr()
  10. @Override void makeSound()

    98Animal cat = new Animal() {99    @Override100    void makeSound() {101        System.out.println("Meow!");102    }
    outputMeow!
  11. 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]
  12. 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}
  13. @Override public int compare(String s1, String s2)

    pass 1 of 6
    25Comparator<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
    passs1s2
    1elephantcat
    2dogelephant
    3dogelephant
    4dogcat
    5butterflydog
    6butterflyelephant
  14. strings ← [cat, dog, elephant, butterfly]

    32    Collections.sort(strings→ [cat, dog, elephant, butterfly], lengthComparator⟨SortingDemo$1 F⟩);33}
  15. 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]
  16. 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}
  17. last1 ← t, last2 ← t

    pass 1 of 6
    37Collections.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
    passs1s2last1last2
    1elephantcattt
    2dogelephantgt
    3dogelephantgt
    4dogcatgt
    5butterflycatyt
    6butterflyelephantyt
  18. 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}
  19. 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 ---
  20. this.listener ← ⟨AnonymousClass$5 H⟩

    55public void setOnClickListener(ClickListener listener⟨AnonymousClass$5 H⟩) {56    this.listener→ ⟨AnonymousClass$5 H⟩ = listener⟨AnonymousClass$5 H⟩;57}
  21. 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();
  22. if (listener != null)

    pass 1 of 3
    59public void click() {60    if (listener⟨AnonymousClass$5 H⟩ != null) {61        listener.onClick();62    }
  23. clickCount ← 1

    pass 1 of 3
    60        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: 1
    All 3 passes — pass 1 is the card above
    passclickCount
    10 1
    21 2
    32 3
  24. button.click();

    144button.click();145button.click();146button.click();
  25. button.click();

    144button.click();145button.click();146button.click();
  26. 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 ---
  27. for (int i = 0; i < times; i++)

    pass 1 of 3
    155public void run() {156    for (int i0 = 0; i < times3; i++) {157        System.out.println(messageHello);158    }
    outputHello
    All 3 passes — pass 1 is the card above
    passi
    10
    21
    32
  28. 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)
  1. 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 ---
  2. @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?
  3. formalGreeting.greet("Sir");

    86formalGreeting.greet("Sir");87casualGreeting.greet("buddy");
  4. @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?
  5. 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 method
    output
    --- Extending Abstract Class ---
  6. @Override void makeSound()

    91Animal dog = new Animal() {92    @Override93    void makeSound() {94        System.out.println("Woof woof!");95    }
    outputWoof woof!
  7. dog.makeSound();

    110dog.makeSound();111dog.sleep();  // Inherited method
  8. void sleep()

    15void sleep() {16    System.out.println("Zzz...");17}
    outputZzz...
  9. dog.sleep(); // Inherited method

    110dog.makeSound();111dog.sleep();  // Inherited method112113cat.makeSound();114// cat.purr();  // Cannot call - Animal doesn't have purr()
  10. @Override void makeSound()

    98Animal cat = new Animal() {99    @Override100    void makeSound() {101        System.out.println("Meow!");102    }
    outputMeow!
  11. 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]
  12. 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}
  13. @Override public int compare(String s1, String s2)

    pass 1 of 6
    25Comparator<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
    passs1s2
    1elephantcat
    2dogelephant
    3dogelephant
    4dogcat
    5butterflydog
    6butterflyelephant
  14. strings ← [cat, dog, elephant, butterfly]

    32    Collections.sort(strings→ [cat, dog, elephant, butterfly], lengthComparator⟨SortingDemo$1 F⟩);33}
  15. 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]
  16. 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}
  17. last1 ← t, last2 ← t

    pass 1 of 6
    37Collections.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
    passs1s2last1last2
    1elephantcattt
    2dogelephantgt
    3dogelephantgt
    4dogcatgt
    5butterflycatyt
    6butterflyelephantyt
  18. 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}
  19. 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 ---
  20. this.listener ← ⟨AnonymousClass$5 H⟩

    55public void setOnClickListener(ClickListener listener⟨AnonymousClass$5 H⟩) {56    this.listener→ ⟨AnonymousClass$5 H⟩ = listener⟨AnonymousClass$5 H⟩;57}
  21. 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();
  22. if (listener != null)

    pass 1 of 3
    59public void click() {60    if (listener⟨AnonymousClass$5 H⟩ != null) {61        listener.onClick();62    }
  23. clickCount ← 1

    pass 1 of 3
    60        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: 1
    All 3 passes — pass 1 is the card above
    passclickCount
    10 1
    21 2
    32 3
  24. button.click();

    144button.click();145button.click();146button.click();
  25. button.click();

    144button.click();145button.click();146button.click();
  26. 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 ---
  27. for (int i = 0; i < times; i++)

    155public void run() {156    for (int i0 = 0; i < times1; i++) {157        System.out.println(messageHello);158    }
    outputHello
  28. 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)
  1. 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 ---
  2. @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?
  3. formalGreeting.greet("Sir");

    86formalGreeting.greet("Sir");87casualGreeting.greet("buddy");
  4. @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?
  5. 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 method
    output
    --- Extending Abstract Class ---
  6. @Override void makeSound()

    91Animal dog = new Animal() {92    @Override93    void makeSound() {94        System.out.println("Woof woof!");95    }
    outputWoof woof!
  7. dog.makeSound();

    110dog.makeSound();111dog.sleep();  // Inherited method
  8. void sleep()

    15void sleep() {16    System.out.println("Zzz...");17}
    outputZzz...
  9. dog.sleep(); // Inherited method

    110dog.makeSound();111dog.sleep();  // Inherited method112113cat.makeSound();114// cat.purr();  // Cannot call - Animal doesn't have purr()
  10. @Override void makeSound()

    98Animal cat = new Animal() {99    @Override100    void makeSound() {101        System.out.println("Meow!");102    }
    outputMeow!
  11. 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]
  12. 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}
  13. @Override public int compare(String s1, String s2)

    pass 1 of 6
    25Comparator<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
    passs1s2
    1elephantcat
    2dogelephant
    3dogelephant
    4dogcat
    5butterflydog
    6butterflyelephant
  14. strings ← [cat, dog, elephant, butterfly]

    32    Collections.sort(strings→ [cat, dog, elephant, butterfly], lengthComparator⟨SortingDemo$1 F⟩);33}
  15. 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]
  16. 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}
  17. last1 ← t, last2 ← t

    pass 1 of 6
    37Collections.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
    passs1s2last1last2
    1elephantcattt
    2dogelephantgt
    3dogelephantgt
    4dogcatgt
    5butterflycatyt
    6butterflyelephantyt
  18. 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}
  19. 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 ---
  20. this.listener ← ⟨AnonymousClass$5 H⟩

    55public void setOnClickListener(ClickListener listener⟨AnonymousClass$5 H⟩) {56    this.listener→ ⟨AnonymousClass$5 H⟩ = listener⟨AnonymousClass$5 H⟩;57}
  21. 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();
  22. if (listener != null)

    pass 1 of 3
    59public void click() {60    if (listener⟨AnonymousClass$5 H⟩ != null) {61        listener.onClick();62    }
  23. clickCount ← 1

    pass 1 of 3
    60        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: 1
    All 3 passes — pass 1 is the card above
    passclickCount
    10 1
    21 2
    32 3
  24. button.click();

    144button.click();145button.click();146button.click();
  25. button.click();

    144button.click();145button.click();146button.click();
  26. 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 ---
  27. for (int i = 0; i < times; i++)

    pass 1 of 5
    155public void run() {156    for (int i0 = 0; i < times5; i++) {157        System.out.println(messageHello);158    }
    outputHello
    All 5 passes — pass 1 is the card above
    passi
    10
    21
    32
    43
    54
  28. 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.

anonymous class Unnamed class defined and instantiated in one expression. Implements interface or extends class.

Common patterns

Where inner classes shine.

InnerClassPatterns.java
Replay: real traced execution (multi-file project)
// 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
            """);
    }
}
  1. 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 ---
  2. this.start ← 1, this.end ← 5

    11NumberRange(int start1, int end5) {12    this.start→ 1 = start1;13    this.end→ 5 = end5;14}
  3. range ← ⟨NumberRange A⟩

    214System.out.println("--- Iterator Pattern ---");215NumberRange range→ ⟨NumberRange A⟩ = new NumberRange(1, 5);216for (int num : range) {
  4. @Override public boolean hasNext()

    pass 1 of 11
    25@Override26public boolean hasNext() {27    return current1 <= end5;  // Uses outer's end28}
    All 11 passes — pass 1 is the card above
    passcurrent
    11
    21
    32
    42
    53
    63
    74
    84
    95
    105
    116
  5. return current++;

    34    }35    return current1++;36}
  6. for (int num : range)

    pass 1 of 5
    215NumberRange range = new NumberRange(1, 5);216for (int num1 : range⟨NumberRange A⟩) {217    System.out.print(num1 + " ");218}
    output1 
    All 5 passes — pass 1 is the card above
    passnum
    11
    22
    33
    44
    55
  7. return current++;

    34    }35    return current2++;36}
  8. return current++;

    34    }35    return current3++;36}
  9. return current++;

    34    }35    return current4++;36}
  10. return current++;

    34    }35    return current5++;36}
  11. 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 ---
  12. 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: Download
  13. for (int i = 0; i <= 100; i += 25)

    pass 1 of 5
    51// Simulate progress52for (int i0 = 0; i <= 100; i += 25) {53    callback.onProgress(i0);54}
    All 5 passes — pass 1 is the card above
    passiresult
    10
    225
    350
    475
    5100Task completed successfully!
  14. @Override public void onProgress(int percent)

    pass 1 of 5
    52        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
    passpercentiresult
    100
    22525
    35050
    47575
    5100100Task completed successfully!
  15. @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!
  16. 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 ---
  17. this.symbol ← +

    pass 1 of 4
    64private Operation(String symbol+) {65    this.symbol→ + = symbol+;66}
    All 4 passes — pass 1 is the card above
    passsymbolabthis.symbol
    1++
    2--
    3**
    4/10.03.0/
  18. @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    }
  19. 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
  20. @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    }
  21. 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 ---
  22. 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}
  23. 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}
  24. this.headers ← {Content-Type=application/json}

    pass 1 of 2
    145public Builder header(String keyContent-Type, String valueapplication/json) {146    this.headers→ {Content-Type=application/json}.put(keyContent-Type, valueapplication/json);147    return this;148}
  25. this.headers ← {Authorization=Bearer token123, Content-Type=application/json}

    pass 2 of 2
    145public 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}
  26. 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}
  27. 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();
  28. 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/users
  29. if (!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"}
  30. 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 ---
  31. public FileSystem(String rootName)

    200public FileSystem(String rootNameroot) {201    this.root = new Entry(rootName, true);202}
  32. this.name ← root, this.isDirectory ← true, this.children ← []

    pass 1 of 7
    173Entry(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
    passnameisDirectorythis.namethis.isDirectorythis.children
    1roottrueroottrue[]
    2srctruesrctrue[]
    3Main.javafalseMain.javafalsenull
    4Utils.javafalseUtils.javafalsenull
    5testtruetesttrue[]
    6MainTest.javafalseMainTest.javafalsenull
    7README.mdfalseREADME.mdfalsenull
  33. this.root ← ⟨FileSystem$Entry F⟩

    200public FileSystem(String rootName) {201    this.root→ ⟨FileSystem$Entry F⟩ = new Entry(rootName, true);202}
  34. 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);
  35. public Entry getRoot()

    pass 1 of 4
    204public Entry getRoot() {205    return root⟨FileSystem$Entry F⟩;206}
  36. public Entry addChild(String name, boolean isDirectory)

    pass 1 of 6
    179public 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
    passnameisDirectory
    1srctrue
    2Main.javafalse
    3Utils.javafalse
    4testtrue
    5MainTest.javafalse
    6README.mdfalse
  37. 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}
  38. 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);
  39. 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}
  40. 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);
  41. 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}
  42. 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);
  43. 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}
  44. 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);
  45. 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}
  46. test.addChild("MainTest.java", false);

    263FileSystem.Entry test = fs.getRoot().addChild("test", true);264test.addChild("MainTest.java", false);265fs.getRoot().addChild("README.md", false);
  47. 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}
  48. fs.getRoot().addChild("README.md", false);

    264test.addChild("MainTest.java", false);265fs.getRoot().addChild("README.md", false);266267fs.getRoot().print("");
  49. public void print(String indent)

    pass 1 of 7
    188public void print(String indent(empty)) {189    System.out.println(indent(empty) + (isDirectorytrue ? "📁 " : "📄 ") + nameroot);190    if (children != null) {
    output📁 root
    All 7 passes — pass 1 is the card above
    passisDirectorynameindent
    1trueroot(empty)
    2truesrc
    3falseMain.java
    4falseUtils.java (empty)
    5truetest
    6falseMainTest.java (empty)
    7falseREADME.md
  50. if (children != null)

    pass 1 of 3
    189System.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
    passchildren
    1⟨FileSystem$Entry[] H⟩, ⟨FileSystem$Entry K⟩, ⟨FileSystem$Entry M⟩]
    2⟨FileSystem$Entry[] I⟩, ⟨FileSystem$Entry J⟩]
    3⟨FileSystem$Entry[] L⟩]
  51. for (Entry child : children)

    pass 1 of 6
    190if (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
    passchildchildrenindent
    1⟨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)
  52. 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