JavaObject-oriented programmingInheritance and polymorphism

Anonymous classes

What is an anonymous class?

Sometimes developers need to use a small class which 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 to declare and instantiate a class in a single statement without declaring a new named class. Such classes are called anonymous because they don't have name identifiers like String or MyClass (but they have an internal name).

Writing anonymous classes

An anonymous class always implement an interface or extends a class (concrete or abstract). Here is a common syntax to create an anonymous class:

new SuperClassOrInterfaceName() {

    // fields

    // overridden methods
};

The syntax of an anonymous class is similar to a constructor call, except that there is a class definition contained in a block of code.

Important: an anonymous class must override all abstract methods of the superclass. That is, all interface methods must be overridden. If an anonymous extends a class that has no any abstract methods, it has the right, not to override anything.

Example. 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 inside a method. 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
    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 which 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 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

Often, after creating an instance of an anonymous class we pass it to a method as an argument. In this case, the anonymous class is called the callback. It's a piece of executable code that is passed to other code, which executes it (perform a call back) at some convenient time.

Let's consider an example. There is a special kind of calculators that can only divide numbers. The calculator takes a callback as its argument and executes the callback passing the result of calculation or an error message.

The Callback interface has two abstract methods:

interface Callback {

    /**
     * Takes a result and process it
     */
    void calculated(int result);

    /**
     * Takes an error message
     */
    void failed(String errorMsg);
}

The class Divider 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, but they 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) {
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);
    }
}

As you can see, we instantiate and pass the callback without any additional variables of the Callback type. It's very common practice for working with callbacks, especially if they are small.

The callback captures the static method print and the local variables a and b from its context. The variables a and b are effectively final here.

Let's run the program.

The input 1:
8 2

The output 1:
8 / 2 is 4

The input 2:
10 0

The 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.
How did you like the theory?
Report a typo