Introduction
An anonymous class in Java is an inner class without a name that allows you to declare and instantiate a class at the same time. It is commonly used to provide a concise implementation of an interface or to extend a class—typically for one-time use cases such as event listeners, thread creation, or functional callbacks. Anonymous classes enable developers to write cleaner, more localized code by avoiding the need to define a separate named class when the implementation is short and context-specific. Understanding anonymous classes is essential for working with legacy Java code and for appreciating the evolution toward lambda expressions in modern Java.
1. When to Use Anonymous Classes
Use anonymous classes when:
- You need to implement an interface with a single method (or a few methods) for a one-off use.
- You want to extend a class and override one or more methods without creating a full subclass.
- The implementation is short and self-contained.
- You are working with APIs that expect callback objects (e.g., GUI event handling, threading).
Note: In Java 8+, lambda expressions are preferred over anonymous classes for functional interfaces (single-method interfaces).
2. Syntax
A. Implementing an Interface
InterfaceName obj = new InterfaceName() {
// Implement interface methods
@Override
public void methodName() {
// Implementation
}
};
B. Extending a Class
ClassName obj = new ClassName() {
// Override methods
@Override
public void methodName() {
// Custom implementation
}
};
Key Points:
- The class has no name.
- It must extend a class or implement an interface.
- It is instantiated immediately (note the
newand the{}block).- It can access final or effectively final variables from the enclosing scope.
3. Common Use Cases
A. Implementing Functional Interfaces (Pre-Lambda)
// Runnable interface (single abstract method: run())
Runnable task = new Runnable() {
@Override
public void run() {
System.out.println("Task executed in anonymous class");
}
};
new Thread(task).start();
B. Event Handling in GUI (Swing Example)
JButton button = new JButton("Click Me");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Button clicked!");
}
});
C. Extending a Class
// Extending Thread class
Thread thread = new Thread() {
@Override
public void run() {
System.out.println("Running in custom thread");
}
};
thread.start();
D. Providing Comparator Implementation
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return b.compareTo(a); // Reverse order
}
});
4. Accessing Variables from Enclosing Scope
Anonymous classes can access:
- Instance and static variables of the enclosing class.
- Local variables of the enclosing method—but only if they are final or effectively final.
Example: Effectively Final Variable
public void process() {
String prefix = "Hello"; // Effectively final (not reassigned)
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println(prefix + " from anonymous class");
}
};
r.run();
}
Why "effectively final"?
The Java compiler requires that local variables used in anonymous classes do not change after the anonymous class is created—this ensures thread safety and consistent behavior.
Invalid Example
public void badExample() {
String message = "Start";
message = "End"; // Reassigned → not effectively final
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println(message); // ❌ Compilation error
}
};
}
5. Anonymous Classes vs. Lambda Expressions (Java 8+)
For functional interfaces (interfaces with one abstract method), lambdas provide a more concise syntax.
Anonymous Class
Runnable r = new Runnable() {
public void run() {
System.out.println("Hello");
}
};
Lambda Equivalent
Runnable r = () -> System.out.println("Hello");
When to Prefer Anonymous Classes
- The interface has more than one abstract method.
- You need to override multiple methods of a class.
- You need to add instance variables or additional methods (not possible with lambdas).
6. Limitations of Anonymous Classes
- Cannot define constructors (since the class has no name).
- Cannot be reused—designed for one-time use.
- Harder to debug—stack traces show synthetic names like
MyClass$1. - Can cause memory leaks if they hold references to outer class instances (in non-static contexts).
- Verbose syntax compared to lambdas for simple cases.
7. Best Practices
- Prefer lambda expressions for functional interfaces (Java 8+).
- Use anonymous classes only when necessary—e.g., for multi-method interfaces or class extension.
- Keep implementations short—if logic grows, refactor into a named class.
- Avoid capturing large objects from the enclosing scope to prevent memory leaks.
- Document the purpose—anonymous classes can reduce readability if overused.
8. Practical Example: Custom Comparator
import java.util.*;
public class Product {
String name;
double price;
Product(String name, double price) {
this.name = name;
this.price = price;
}
@Override
public String toString() {
return name + " ($" + price + ")";
}
public static void main(String[] args) {
List<Product> products = Arrays.asList(
new Product("Laptop", 1200),
new Product("Mouse", 25),
new Product("Keyboard", 75)
);
// Sort by price using anonymous class
Collections.sort(products, new Comparator<Product>() {
@Override
public int compare(Product p1, Product p2) {
return Double.compare(p1.price, p2.price);
}
});
System.out.println(products);
// Output: [Mouse ($25.0), Keyboard ($75.0), Laptop ($1200.0)]
}
}
Conclusion
Anonymous classes are a powerful feature in Java that enable on-the-spot implementation of interfaces or extension of classes without boilerplate code. While largely superseded by lambda expressions for single-method interfaces in modern Java, they remain relevant for multi-method scenarios, class inheritance, and legacy codebases. By understanding their syntax, scoping rules, and limitations, developers can use anonymous classes judiciously to write concise and expressive code. However, always consider whether a lambda, method reference, or named class would be clearer—clarity and maintainability should guide your choice. Mastering anonymous classes provides deeper insight into Java’s object model and prepares you for both historical and contemporary Java development.