1. Introduction to anonymous classes
Imagine you have a class Animal that describes how an animal behaves. This class has a method say() that prints "The animal makes a sound". You need to create an object that will behave like a dog and print "Woof!", but you don’t want to create a separate Dog.java file for that.
This is where anonymous classes come to the rescue. These are classes without a name that are declared and instantiated right at the point of use. 🚀 They let you inherit a class “on the fly,” without creating a separate file. Instead of creating many small class files that are used only in one place, you can simply write all the logic right where it’s needed.
What does the syntax look like?
The syntax of anonymous classes may seem unusual, but it’s actually quite simple:
VariableType name = new TypeForInheritance() {
// Here we write the body of the anonymous class
// Override the parent class's methods
};
Let’s break this syntax down:
- VariableType name: This is a regular variable declaration where we store our new object.
- new TypeForInheritance(): Here we’re seemingly creating a new object. But instead of a class name, we use the name of the class we want to extend. Note: after the parentheses () there is no semicolon !
- { ... }: Here we open curly braces and write all the logic of our anonymous class. We can override the parent class’s methods or add our own logic.
Example of inheriting from a regular class:
Let’s return to our animal example.
class Animal {
void say() {
System.out.println("The animal makes a sound");
}
}
// Create an anonymous class by extending Animal
Animal dog = new Animal() {
// Override the say() method
@Override
void say() {
System.out.println("Woof-woof! 🐶");
}
};
Animal cat = new Animal() {
@Override
void say() {
System.out.println("Meow-meow! 🐱");
}
};
dog.say(); // Prints: Woof-woof! 🐶
cat.say(); // Prints: Meow-meow! 🐱
In this example, we created two objects, dog and cat, which are essentially anonymous classes that extend Animal. At the same time, we didn’t create a single separate file.
Comparing approaches
// The usual way (create a separate class)
class Dog extends Animal {
@Override
void say() { System.out.println("Woof!"); }
}
Animal dog = new Dog();
// VS
// Anonymous class (all in one place)
Animal dog = new Animal() {
@Override
void say() { System.out.println("Woof!"); }
};
The result is the same, but the anonymous class is shorter and doesn’t clutter the project!
2. The name of an anonymous class after compilation
Anonymous classes have no name in the source code, but the Java compiler, of course, still has to name them somehow to create a .class file. It does so according to a strict rule:
- The file name of an anonymous class consists of the name of the outer class in which it was declared.
- After the outer class name, a dollar sign $ is added.
- Then comes the ordinal number of the anonymous class in this file, starting from 1.
Thus, if our animal example is in the file Main.java, then after compilation three files will be created:
- Main.class
- Main$1.class (our anonymous class for the dog)
- Main$2.class (our anonymous class for the cat)
If an anonymous class is declared inside a method that itself resides in an inner class, the name will look more complex, for example, OuterClass$InnerClass$1.class.
This is an internal compiler convention that’s useful to know about, but in day-to-day development it rarely matters. The main thing is to remember that an anonymous class is still a full-fledged class, even though it has no name in the source code.
3. Important features and limitations
Anonymous classes are a powerful tool, but they have their own rules.
Access to variables. An anonymous class can use variables from the surrounding method. However, these variables must be final or effectively final (that is, their value doesn’t change after initialization).
public void doSomething() {
String greeting = "Hello!"; // This variable is effectively final
class OuterClass {
void greet() {
// Create an anonymous class inside the method
new Object() {
void sayHello() {
System.out.println(greeting); // This is allowed
// greeting = "Goodbye!"; // And this will cause an error!
}
}.sayHello();
}
}
new OuterClass().greet();
}
Why so? Because an anonymous class can outlive the method itself, and if it could change the variable, it would lead to problems.
No constructor. Since an anonymous class has no name, it cannot have a constructor. But you can use an initializer block to run code when the object is created:
Animal dog = new Animal() {
// Initialization block
{
System.out.println("Anonymous class initialization 🐶");
}
@Override
void say() {
System.out.println("Woof-woof!");
}
};
Restrictions. Anonymous classes cannot declare static fields (except constants) or methods. They are always created as part of another object, so they cannot be static, public, protected or private.
4. Useful nuances
When to use anonymous classes
- You need to extend a class (or implement an interface) just once.
- The implementation is small — 1–2 methods, no more than a couple dozen lines.
- The class is needed only in one place and there’s no point in giving it a name.
- You want to avoid cluttering the package with many tiny one-off classes.
Typical scenarios:
- Event handlers (GUI, Swing, Android, etc.).
- Passing callbacks to methods.
- Quick comparator implementations for sorting collections.
- Temporary modified objects (e.g., for tests).
5. Interaction with the outer class
If an anonymous class is declared inside a non-static method or block of the outer class, it can access the fields and methods of that outer class (including private ones!).
public class Outer {
private String secret = "Secret text";
// Base class
class Printer {
public void print() {
System.out.println("Regular output");
}
}
public void revealSecret() {
Printer p = new Printer() {
@Override
public void print() {
System.out.println("Access to private: " + secret);
}
};
p.print();
}
public static void main(String[] args) {
new Outer().revealSecret();
}
}
6. Common mistakes when working with anonymous classes
Error #1: trying to modify a variable from the enclosing method.
If you declared a variable outside the anonymous class and try to change it after it has been used inside the anonymous class, the compiler will report an error. The variable must be final or effectively final (not change after initialization).
Error #2: an anonymous class that’s too large.
If an anonymous class has grown to dozens of lines and contains several methods, that’s a signal to extract it into a separate named class. Otherwise, the code will become unreadable.
Error #3: trying to use static methods or fields.
You can’t declare static methods or fields (except constants) in an anonymous class. If you really need them, that’s a reason to create a regular nested class.
Error #4: forgetting about scope.
An anonymous class is visible only where it is declared and has no name. If you need to use it multiple times, declare a regular class.
GO TO FULL VERSION