Anonymous Classes in Java
Anonymous Classes
Anonymous classes are a type of inner class that is declared and instantiated at the same time. It is a type of inline inheritance. They can be local variables, instance variables, or class variables. You can create anonymous classes using an interface, an abstract class, or a concrete class. You cannot create them using sealed classes or sealed interfaces.
Anonymous classes are similar to local classes but do not have a name. Because they don't have a name, they cannot be used to create other instances of that anonymous class. Also, local classes are declarations, whereas anonymous classes are expressions.
Anonymous Class Syntax
The syntax for creating an anonymous class is the same as creating an instance of a class. The difference is it ends with open and close braces before the semicolon. Inside the braces is the body of the anonymous class.
final User user = new User() {
};
In this example, the superclass of the user variable would be User.
In the previous example, the Java compiler will generate a .class file for this anonymous class with a name similar to press.bytesize.domain.User$1.
Constructors
When creating anonymous classes, you can use any constructor declared on the class you are creating an anonymous class from. For example, the following class has two constructors.
public class User {
private String id;
private String firstName;
private String lastName;
public User(final String id) {
// ...
}
public User(final String firstName, final String lastName) {
// ...
}
}
Creating instances of an anonymous class with either one of these constructors would look like the following:
final var user1 = new User("userId") {
// ...
};
final var user2 = new User("firstName", "lastName") {
// ...
};
If there isn't a constructor in the case of an interface, you call a default no-args constructor.
final var interface = new MyInterface() {
// ...
}
Anonymous classes cannot define their own constructors; however, anonymous classes do support initializers. They are written the same way as they are in a class.
final var user = new User() {
{
setFirstName("first");
setLastName("last");
}
}
Methods
You can implement methods, override methods, and create your own non-static methods in an anonymous class. You cannot create static methods.
Implementing Methods
When creating an anonymous class using an interface, you can create an implementation for each of the methods in that interface. You can also do this with an abstract method in an abstract class. Here is an example.
public interface MyInterface {
void method1();
void method2();
}
final var anonymous = new MyInterface() {
@Override
public void method1() {
// ...
}
@Override
public void method2() {
// ...
}
}
Overriding Methods
You can override methods in an anonymous class and make calls to the superclass using super with the following:
final var anonymous = new MyClass() {
@Override
public void input(final byte[] value) {
// ...
}
@Override
public byte[] output() {
final byte[] result = super.output();
// ...
}
}
This overrides both the output() method and the input() method. In the output() method, there is a call to the superclasses output() method using super.
Adding Methods
You can create custom non-static methods in anonymous classes just like you do in a normal class.
final var myClass = new MyClass() {
{
customMethod();
}
private void customMethod() {
// ...
}
}
Even though myClass is an anonymous class, the type is still MyClass. Methods added to the anonymous class are not available to the MyClass type.
Variables
Variables that are in scope outside of the anonymous class can be used inside the anonymous class. Anonymous classes support class variables, instance variables, and local variables. When creating an anonymous class, you can declare instance variables inside the anonymous class.
final var user = new User() {
private int version;
}
You can then use these variables inside the anonymous class just like you can in a normal class.
Conclusion
Anonymous classes are unnamed inner classes and a type of inner inheritance. They allow you to implement or override methods in a class or interface. They do not allow you to define new constructors but allow you to still use initializers.