Java Anonymous Class
Sometimes developers need to use a small class that overrides some methods of another class or interface only once. In this case, declaring a new class may be superfluous. Fortunately, Java provides a mechanism for creating a class in a single statement without having to declare a new named class. Such classes are called anonymous because they don't have name identifiers like String
or MyClass
(but they do have an internal name).
What is an anonymous class?
Anonymous classes enable you to declare and instantiate a class at the same time.
An anonymous class always implements an interface or extends another class (either concrete or abstract class). Here is the common syntax for creating an anonymous class:
new SuperClassOrInterfaceName() {
// fields
// overridden methods
};
The syntax of an anonymous class is an expression. And it's similar to a constructor call except that there is a class definition contained in a block of code.
An anonymous class must override all abstract methods of the superclass. That is, all interface methods must be overridden except default methods. If an anonymous class extends a class that has no abstract methods, it doesn't have to override anything.
Writing anonymous classes
Let's assume we have the following interface with two methods:
interface SpeakingEntity {
void sayHello();
void sayBye();
}
Here is an anonymous class that represents an English-speaking person:
SpeakingEntity englishSpeakingPerson = new SpeakingEntity() {
@Override
public void sayHello() {
System.out.println("Hello!");
}
@Override
public void sayBye() {
System.out.println("Bye!");
}
};
The anonymous class is declared and instantiated at the same time — as a single expression. It overrides both methods of the interface.
We assign an instance of the anonymous class to the variable of the interface type. Now, we can invoke overridden methods:
englishSpeakingPerson.sayHello();
englishSpeakingPerson.sayBye();
Of course, the result is:
Hello!
Bye!
Let's declare and instantiate another anonymous class:
SpeakingEntity cat = new SpeakingEntity() {
@Override
public void sayHello() {
System.out.println("Meow!");
}
@Override
public void sayBye() {
System.out.println("Meow!");
}
};
When we invoke the same methods, we obtain the following result:
Meow!
Meow!
So, englishSpeakingPerson
and cat
are instances of different anonymous classes that implement the same interface.
Accessing context variables
In the body of an anonymous class, it is possible to capture variables from a context where it is defined:
- an anonymous class can capture members of its enclosing class (the outer class);
- an anonymous class can capture local variables that are declared as
final
or are effectively final (i.e. the variable is not changed even though it doesn't have thefinal
keyword).
Here is another anonymous class that implements the SpeakingEntity
interface:
public class AnonymousClassExample {
private static String BYE_STRING = "Auf Wiedersehen!"; // static constant
public static void main(String[] args) {
final String hello = "Guten Tag!"; // final local variable
SpeakingEntity germanSpeakingPerson = new SpeakingEntity() {
@Override
public void sayHello() {
System.out.println(hello); // it captures the local variable
}
@Override
public void sayBye() {
System.out.println(BYE_STRING); // it captures the constant field
}
};
germanSpeakingPerson.sayHello();
germanSpeakingPerson.sayBye();
}
}
The anonymous class captures the constant field BYE_STRING
and the local final variable – hello
. This code is successfully compiled and prints what we expect:
Guten Tag!
Auf Wiedersehen!
A declaration of a variable or a method in an anonymous class shadows any other declaration in the enclosing scope that has the same name. You cannot access any shadowed declarations by their names.
When to use anonymous classes
Generally, you should consider using an anonymous class feature when:
- only one instance of the class is needed;
- the class body is very short;
- the class is used right after it's defined.
In this topic, we've considered rather simple anonymous classes to understand the basic syntax, but in real-life applications, they provide a powerful mechanism for creating classes that encapsulate behaviors and pass them to suitable methods. This is a convenient way to interact with parts of our application or with some third-party libraries.
How to create?
The most popular way to create an anonymous class is to implement an interface and you have seen it already. So, now let's try something new — let's create an anonymous class that inherits from another class.
Imagine a human: they have a brain and many-many thoughts in it. Every couple of seconds the brain produces a new thought. If we want to describe this in Java, how will we do it?
abstract class HumanThought {
public void print() {
System.out.println("This is a very important thought.");
}
}
HumanThought
is our superclass that has one method for printing the standard thought. And now anonymous classes will help us. By inheriting from HumanThought
, we may have as many different thoughts as we want — and that's all without creating new .java
files.
All new thoughts would be children of our superclass and will have their own method print:
class Human {
public void takeMilkshake() {
// creation of anonymous class by inheriting from class HumanThought
HumanThought thought = new HumanThought() {
public void print() {
System.out.println("What to take? Chocolate or strawberry milkshake..");
}
};
thought.print();
}
}
And if we wanted to create an actual human and invoke method takeMilkshake
— what would be the output?
public class Main {
public static void main(String[] args) {
Human human = new Human();
human.takeMilkshake();
}
}
Of course, you are thinking the right thought:
What to take? Chocolate or strawberry milkshake..
And have you noticed that the HumanThought
class is abstract? Yes, it is — don't forget that we can create an anonymous class by inheriting from both concrete and abstract classes.
But to become a master in programming you should get acquainted with another case of creating anonymous classes: when we create an anonymous class and pass it in a constructor as an argument.
So, what is going on in our example below? Firstly, Thread
is a standard Java class. And if you don't know each other yet, don't be afraid — fruitful cooperation awaits you. And Runnable
is an interface that describes some action — any action you want. In our example, Runnable
has an action that only prints a phrase.
Thread
has several constructors, that is a normal situation, and one of its constructors take as an argument an anonymous class that implements the Runnable
interface.
As a result, the anonymous class is passed as an argument of the constructor:
class MyExample {
public static void main(String[] args) {
//Anonymous class is created as a constructor argument
Thread t = new Thread(new Runnable() {
public void run() {
System.out.println("Run, Forrest, run!");
}
});
}
}
Learn callbacks by example
Often, after creating an instance of an anonymous class we pass it to some method as an argument. In this case, the anonymous class is called a callback. A callback is a piece of executable code that is passed to another code that executes it (performs a call back) at a convenient time. And can we call our previous example a callback? Yes, we can — because the constructor is a special method.
Let's consider an example. There is a special kind of calculator that can only divide numbers. The calculator takes a callback as its argument and executes the callback passing the result of the calculation or an error message.
The Callback
interface has two abstract methods:
interface Callback {
/**
* Takes a result and processes it
*/
void calculated(int result);
/**
* Takes an error message
*/
void failed(String errorMsg);
}
The Divider
class has only one static method (just an example, the demonstrated technique works with any methods):
class Divider {
/**
* Divide a by b. It executes the specified callback to process results
*/
public static void divide(int a, int b, Callback callback) {
if (b == 0) {
callback.failed("Division by zero!");
return;
}
callback.calculated(a / b);
}
}
Of course, in this case, you can perform the division and return the result without any callbacks. In general, callbacks can help you in large applications with multiple parts and layers (especially in multithreaded programs).
Calling a method with a callback:
public class CallbacksExample {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int a = scanner.nextInt();
int b = scanner.nextInt();
Divider.divide(a, b, new Callback() { // passing callback as an argument
@Override
public void calculated(int result) {
String textToPrint = String.format("%d / %d is %d", a, b, result);
print(textToPrint);
}
@Override
public void failed(String errorMsg) {
print(errorMsg);
}
});
}
public static void print(String text) {
System.out.println(text);
}
}
As you can see, we instantiate and pass the callback without any additional variables of the Callback
type. It's a very common practice for working with callbacks, especially if they are small.
The callback captures the static print
method and the local variables a
and b
from its context. The variables a
and b
are effectively final here (i.e. the variables aren't changed so you don't need to write the final
keyword).
Let's run the program.
Input 1:
8 2
Output 1:
8 / 2 is 4
Input 2:
10 0
Output 2:
Division by zero!
So, anonymous classes along with the context capture mechanism allow you to transfer logic between parts of your program. They are used as callbacks in large applications and when working with external libraries.
Restrictions on anonymous classes
And of course, anonymous classes have some restrictions that you should take into consideration:
- they cannot have static initializers or interface declarations;
- they cannot have static members, except constant variables (
final static
fields); - they cannot have constructors.
Let's consider the following example with an anonymous class that extends SpeakingEntity
. To not have static initializers, static members, or interface declarations — it's not a big deal. But what about not having a constructor? How can we initialize our fields?
final String robotName = "Bug";
final int robotAssemblyYear = 2112;
SpeakingEntity robot = new SpeakingEntity() {
static final int MAGIC_CONSTANT = 10;
private String name;
private int assemblyYear;
{ /* instance initialization block for setting fields */
name = robotName;
assemblyYear = robotAssemblyYear;
}
@Override
public void sayHello() {
System.out.println("1010001" + MAGIC_CONSTANT);
}
@Override
public void sayBye() {
System.out.println("0101110" + MAGIC_CONSTANT);
}
};
And for examples like this one, you should be friends with the good old theory! Remember about instance initializers and what they are for? Yes, instance initializer allows us to substitute a constructor. It runs each time when an object of the class is created. So, name
and assemblyYear
fields will be initialized and our robot will have the name "Bug" and a year of birth!
Summary
Perhaps you are wondering where to go in order to see how anonymous classes are used in "real life"? In that case, we have a suggestion.
Anonymous classes are actively used when writing user interfaces with the standard Java library called Swing. The same with developing a web user interface using Google Web Toolkit (GWT). It is very common to have a lot of listeners that are used just once for one button, so using anonymous classes allows us to avoid writing a lot of classes and having useless files during code development.
Some widespread libraries for working through the HTTP protocol also use anonymous classes. For example, the HttpAsyncClient module.
And at last — what are the advantages of anonymous classes? Anonymous classes enable you to make your code more concise and reduce the number of .java
files. And what about encapsulation? Each anonymous class has very local scope. It is defined exactly where it is needed and it can never be used anywhere else. So, it definitely increases encapsulation and gives you another reason to fall in love with Java!