Java Anonymous Inner Classes
Create one-off implementations of interfaces and abstract classes in Java with anonymous inner classes.
An anonymous class is a one-shot subclass or interface implementation that you define and instantiate in a single expression — no name, no separate file, no class header. They were how Java handled callbacks, listeners, and small adapters before lambdas existed in Java 8. Lambdas have replaced most of their use cases, but anonymous classes are still legal, still useful in a few specific situations, and still show up in older codebases.
The syntax
The form is new SomeType() { ... body ... }. The body is the class definition; the surrounding expression also creates an instance:
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("hi");
}
};
r.run();That single statement (1) defines a new class that implements Runnable, (2) creates one instance of it, (3) assigns the instance to r. The class has no name in your source code; the compiler gives it a generated name like Outer$1 in the .class file.
You can do the same with an abstract class:
Shape s = new Shape() {
@Override double area() { return 42; }
};…or even a concrete class, if you want to override one of its methods inline:
ArrayList<String> chatty = new ArrayList<>() {
@Override
public boolean add(String s) {
System.out.println("added " + s);
return super.add(s);
}
};When you'd use one
The classic case: a callback whose implementation is tiny and used in exactly one place:
button.addClickListener(new ClickListener() {
@Override
public void onClick() {
System.out.println("clicked");
}
});In modern Java, you'd usually write this as a lambda:
button.addClickListener(() -> System.out.println("clicked"));…and the lambda is shorter, easier to read, and doesn't pin an outer-class reference. So when does the anonymous form still make sense?
- Multiple methods. A lambda implements a single abstract method. If you need to override two methods on an abstract class or implement two on an interface, only an anonymous class will do.
- Subclassing a concrete class. Lambdas only target functional interfaces. To override a method on
ArrayList,HashMap, or your own concrete class on the fly, you need an anonymous class. - Calling
super.method(...)in the override. Lambdas have nosuper. Anonymous classes do. - Initialization blocks. Anonymous classes can have instance initializer blocks (
{ ... }); lambdas cannot.
In practice that's a small set of cases. Most modern callbacks use lambdas.
Capturing variables
An anonymous class declared inside a method can read the enclosing method's local variables — but only if they're final or effectively final (never reassigned after their initialization):
void schedule() {
String msg = "hello";
Runnable r = new Runnable() {
@Override public void run() {
System.out.println(msg); // captures msg
}
};
r.run();
// msg = "bye"; // would make msg no longer effectively final → ERROR above
}The same rule applies to lambdas — it's a property of the surrounding code, not the syntactic form. The reason is that the captured value is copied into the synthetic class's fields; if msg could change later, the captured copy would silently go out of date.
They have an outer this
Like inner classes, anonymous classes declared in a non-static context carry a reference to the enclosing instance. That means this inside the anonymous class refers to the anonymous instance, not the outer one. To reach the outer instance, qualify it with Outer.this:
public class Server {
String name = "outer";
Runnable handler() {
return new Runnable() {
String name = "inner";
public void run() {
System.out.println(name); // "inner"
System.out.println(Server.this.name);// "outer"
}
};
}
}And same outer-reference caveat as inner classes: returning an anonymous instance to long-lived code keeps the outer instance alive.
Limitations
- An anonymous class can extend one superclass or implement one interface — not both, and not more than one of either.
- It cannot have a constructor of its own — there's no name to give the constructor. You can use an instance initializer block (
{ ... }) for setup. - It cannot be
static.
Compared to lambdas — the comparison in code
Same job, two ways:
// Anonymous class — older style
Comparator<String> byLength = new Comparator<String>() {
@Override
public int compare(String a, String b) {
return Integer.compare(a.length(), b.length());
}
};
// Lambda — modern equivalent
Comparator<String> byLength = (a, b) -> Integer.compare(a.length(), b.length());Both produce a Comparator<String>. The lambda is shorter and has slightly different this/scoping semantics (no outer-class reference for instance contexts; this inside a lambda is the enclosing instance, not a new object). If both forms work for your use case, prefer the lambda.
A worked example
What's next
The remaining nested-class flavor is the local class — a class declared inside a method body, with a real name but a tiny scope. They overlap with anonymous classes (and with lambdas), but they're occasionally the cleanest choice. Continue to local classes.
Practice
In modern Java, which task still requires an anonymous class rather than a lambda?