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
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
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);
}
}
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:
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");
}
}
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:
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());
}
}
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
abstractorstatic, 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
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();
}
}
anonymous class: this = anonymous object lambda: this = outer object
| Aspect | Anonymous class | Lambda |
|---|---|---|
| Can implement | Any interface, or extend a class | Functional interfaces only |
| Methods | Any number | Exactly one |
| Own state (fields) | Yes | No |
this refers to | The anonymous object | The enclosing object |
| Class file | One per anonymous class (Outer$1.class) | None; generated at run time via invokedynamic |
| Verbosity | High | Low |
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; useList.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
Frequently Asked Questions (FAQ)
Q1. What is an anonymous inner class in Java?
A class without a name, declared and instantiated in a single expression, that implements an interface or extends a class.
Q2. Can an anonymous class have a constructor?
No, because constructors need the class name. Use an instance initializer block, or pass arguments to the superclass constructor.
Q3. Can an anonymous class implement multiple interfaces?
No. It can implement exactly one interface or extend exactly one class.
Q4. Can an anonymous class extend a class and implement an interface?
No. It has exactly one direct supertype. Use a local or nested class if you need both.
Q5. What is the difference between an anonymous class and a lambda?
A lambda implements only a functional interface, has no state and shares the enclosing this. An anonymous class can extend classes, have several methods and fields, and has its own this.
Q6. Can an anonymous class access local variables?
Yes, if they are final or effectively final.
Q7. What is the class file name of an anonymous class?
Outer$1.class, Outer$2.class and so on, numbered in order of appearance.
Q8. Can an anonymous class extend an abstract class?
Yes. It must implement all abstract methods. This is the usual way to "instantiate" an abstract class inline.
Q9. Can an anonymous class have static members?
Since Java 16, yes. Earlier versions allowed only static constants.
Q10. Can I add new methods to an anonymous class?
Yes, but they can only be called from inside the class or through a var variable, because the reference type is the supertype.
Q11. Does an anonymous class hold a reference to the outer object?
Yes, when created in an instance method or initializer. This can cause memory leaks if the anonymous object lives longer than the outer one.
Q12. Can the diamond operator be used with anonymous classes?
Yes, since Java 9, as long as the inferred type is denotable.
Q13. What does this mean inside an anonymous class?
The anonymous class instance itself. Use Outer.this to refer to the enclosing object.
Q14. What is double brace initialization?
Creating an anonymous subclass with an initializer block, as in new HashMap<>() {{ put("a", 1); }}. It is considered an anti-pattern; use Map.of instead.
Q15. Where are anonymous classes still useful?
For extending abstract classes inline, implementing interfaces with multiple methods (such as some listeners), and keeping state between calls.
Q16. Can an anonymous class be generic?
It cannot declare its own type parameters, but it can implement or extend a parameterized type, such as new Comparator<String>() { ... }.
Q17. Is an anonymous class final?
Effectively yes. It cannot be extended because it has no name.
Q18. Can an anonymous class be declared in a static method?
Yes. It then has no outer instance and can only access the outer class's static members.
Q19. Are anonymous classes slower than lambdas?
Both perform similarly at run time. Anonymous classes create extra class files and an object per evaluation, while non-capturing lambdas can reuse a single instance.
Q20. How do I convert an anonymous class to a lambda?
If it implements a functional interface and does not use its own this or fields, replace it with (params) -> body. IDEs can do this automatically.