What is an anonymous class?
Writing anonymous classes
new SuperClassOrInterfaceName() {
// fields
// overridden 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!");
}
};
englishSpeakingPerson.sayHello();
englishSpeakingPerson.sayBye();
Hello!
Bye!
SpeakingEntity cat = new SpeakingEntity() {
@Override
void sayHello() {
System.out.println("Meow!");
}
@Override
public void sayBye() {
System.out.println("Meow!");
}
};
Meow!
Meow!
Accessing context variables
- 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 they are effectively final (i.e. the variable is not changed but has no the final 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 print what we expect:
Guten Tag!
Auf Wiedersehen!
Important: 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.
Restrictions on anonymous classes
Anonymous classes have some restrictions:
- they cannot have static initializers or member interfaces;
- they cannot have static members, except the constant variables (final static fields);
- they cannot have constructors.
For example, let's see the following anonymous class that has a final static field and an instance initializer to substitute a constructor:
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);
}
};
When to use anonymous classes
In common case, you should consider using an anonymous class when:
- only one instance of the class is needed;
- the class has a very short body;
- the class is used right after it's defined.
So, in this topic, we've considered rather simple anonymous classes to understand their base syntax, but in real applications, they give a powerful mechanism to create classes that encapsulate behaviors and pass them to suitable methods. It gives us a convenient way to interact with parts of our application or with some third-party libraries.
For instance, anonymous classes are actively used when writing user interfaces using the standard Java library called Swing. The same thing when developing a web user interface using Google Web Toolkit (GWT). It is very common to have a lot of listeners which are only used just once for one button, so using anonymous classes allows us to avoid writing a lot of classes and having useless files in the development of the code.
Some widespread libraries for working through the HTTP protocol also uses anonymous classes. Here is an example: https://hc.apache.org/httpcomponents-asyncclient-dev/quickstart.html. You may not now understand how to use it, but notice how many anonymous classes there are.
Learn callbacks by example
interface Callback {
/**
* Takes a result and process it
*/
void calculated(int result);
/**
* Takes an error message
*/
void failed(String errorMsg);
}
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);
}
}
public class CallbacksExample {
public static void main(String[] args) {
f a calculation
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);
}
}
8 2
8 / 2 is 4
10 0
Division by zero!