00:00

Anonymous Inner Class in Java – Syntax, Rules and Examples

An anonymous inner class is a class without a name that is declared and instantiated in a single expression. It either implements an interface or extends a class, and is used when you need a one-off implementation that would not be worth a separate named class: a comparator, a listener, a callback or a small override.

Before Java 8, anonymous classes were the standard way to pass behaviour around. Lambdas now cover most of those cases, but anonymous classes are still needed when you extend a class, implement an interface with several methods, or keep state. This tutorial covers all of these and compares the two.

1. Syntax

Syntax
SuperType ref = new SuperType(constructorArgs) {
    // fields, initializer blocks, methods (usually overrides)
};                          // note the semicolon: this is an expression

SuperType is the interface being implemented (then the parentheses are empty) or the class being extended (then the arguments go to its constructor).

2. Implementing an Interface

AnonymousInterface.java
import java.util.*;

public class AnonymousInterface {
    interface Greeting { String greet(String name); }

    public static void main(String[] args) {
        // Anonymous class implementing an interface
        Greeting formal = new Greeting() {
            @Override public String greet(String name) { return "Good morning, " + name + "."; }
        };
        System.out.println(formal.greet("Ms. Rao"));

        // Anonymous Comparator passed directly as an argument
        List<String> cities = new ArrayList<>(List.of("Pune", "Bengaluru", "Delhi", "Kochi"));
        cities.sort(new Comparator<String>() {
            @Override public int compare(String a, String b) { return Integer.compare(a.length(), b.length()); }
        });
        System.out.println("By length: " + cities);
    }
}
Output
Good morning, Ms. Rao.
By length: [Pune, Delhi, Kochi, Bengaluru]

The anonymous Comparator is created right where it is needed, as a method argument. Today you would write cities.sort(Comparator.comparingInt(String::length)), but the anonymous form shows what happens underneath.

3. Extending a Class

An anonymous class can extend an abstract or concrete class. Constructor arguments are passed to the superclass constructor, and super calls work as usual:

AnonymousSubclass.java
public class AnonymousSubclass {
    static abstract class Discount {
        private final String code;
        Discount(String code) { this.code = code; }          // constructor of the superclass
        abstract double apply(double price);
        String code() { return code; }
    }

    static class Logger {
        void log(String msg) { System.out.println("[INFO] " + msg); }
    }

    public static void main(String[] args) {
        // Extending an abstract class; arguments go to the superclass constructor
        Discount festive = new Discount("DIWALI20") {
            @Override double apply(double price) { return price * 0.8; }
        };
        System.out.println(festive.code() + ": 2500 -> " + festive.apply(2500));

        // Extending a concrete class and overriding one method
        Logger loud = new Logger() {
            @Override void log(String msg) { super.log(msg.toUpperCase() + "!"); }
        };
        loud.log("order shipped");
    }
}
Output
DIWALI20: 2500 -> 2000.0
[INFO] ORDER SHIPPED!

This is something lambdas cannot do: they only implement functional interfaces.

4. Fields and Instance Initializers

An anonymous class cannot declare a constructor (it has no name), but it can have fields and an instance initializer block:

AnonymousState.java
import java.util.Iterator;

public class AnonymousState {
    static Iterator<Integer> countdown(int from) {
        // Anonymous class with its own field and an instance initializer
        return new Iterator<>() {                            // diamond allowed since Java 9
            private int current;
            { current = from; }                             // instance initializer instead of constructor

            @Override public boolean hasNext() { return current > 0; }
            @Override public Integer next() { return current--; }
        };
    }

    public static void main(String[] args) {
        Iterator<Integer> it = countdown(5);
        StringBuilder sb = new StringBuilder();
        while (it.hasNext()) sb.append(it.next()).append(' ');
        System.out.println("Countdown: " + sb + "Go!");
        System.out.println("Class name: " + countdown(1).getClass().getName());
    }
}
Output
Countdown: 5 4 3 2 1 Go!
Class name: AnonymousState$1

The compiler names anonymous classes Outer$1, Outer$2 and so on, in order of appearance, and produces a .class file for each.

5. Rules of Anonymous Classes

  • Implements exactly one interface or extends exactly one class, never both and never more.
  • Cannot declare constructors; use an initializer block or the superclass constructor.
  • Cannot be abstract or static, and cannot be reused, as it has no name; it is effectively final.
  • Can access the enclosing method's local variables only if they are final or effectively final.
  • In an instance context, it holds a reference to the outer object and can use its members.
  • Since Java 9, the diamond operator works with anonymous classes (new Iterator<>() { ... }).
  • Since Java 16, it can declare static members.
  • New public methods added in an anonymous class cannot be called through the supertype reference (except via var).

6. Anonymous Class vs Lambda

AnonymousVsLambda.java
public class AnonymousVsLambda {
    private final String name = "outer object";

    void demo() {
        Runnable anon = new Runnable() {
            private final String name = "anonymous object";
            @Override public void run() { System.out.println("anonymous class: this = " + this.name); }
        };
        Runnable lambda = () -> System.out.println("lambda:          this = " + this.name);
        anon.run();
        lambda.run();
    }

    public static void main(String[] args) {
        new AnonymousVsLambda().demo();
    }
}
Output
anonymous class: this = anonymous object
lambda:          this = outer object
AspectAnonymous classLambda
Can implementAny interface, or extend a classFunctional interfaces only
MethodsAny numberExactly one
Own state (fields)YesNo
this refers toThe anonymous objectThe enclosing object
Class fileOne per anonymous class (Outer$1.class)None; generated at run time via invokedynamic
VerbosityHighLow

Use a lambda (or method reference) for functional interfaces; use an anonymous class when you need to extend a class, implement several methods, or keep state.

7. Pitfalls

  • Memory leaks: anonymous classes created in instance methods hold a reference to the outer object, a classic leak with long-lived listeners.
  • "Double brace initialization" (new ArrayList<>() {{ add("a"); }}) creates an anonymous subclass for every use and captures the outer instance; use List.of(...) instead.
  • Readability: long anonymous classes make code hard to follow; extract them into named classes.

8. Summary

  • An anonymous class is an unnamed class declared and instantiated in one expression.
  • It implements one interface or extends one class, and can have fields, methods and initializer blocks but no constructor.
  • It captures effectively final locals and, in instance contexts, the outer object.
  • Prefer lambdas for functional interfaces; keep anonymous classes for subclasses, multiple methods or state.

Related Tutorials