Anonymous Classes

The concept of anonymous classes often confuses Java developers. Essentially,anonymous
classes are limited-scope classes that are declared but are not given a name by
the programmer (hence the designation "anonymous") and have only a limited
lifespan. Although they can be used for a wide variety of applications, they are most
commonly used as event handlers in GUI programs. A common example of an anonymous
class is shown in Example 6-6.

This example declares an anonymous class that listens to and acts on the action
events produced by a button. Because the syntax of the anonymous class is a little
peculiar, it is worth studying in detail.

Anonymous class syntax

Anonymous classes can be used only once, so they must be used as a parameter to a
method or assigned to a variable. Consequently, it is necessary to declare and institute
the class in one move, which is why you start out using the keyword new to
instantiate the class you are declaring. In this case, the anonymous class is declared,
instantiated, and then passed to the addActionListener( ) method of the btn object:

Anonymous classes can use any non-final interface or class as their supertype. If you
use an interface, then the superclass of the anonymous class will automatically be
java.lang.Object (see Chapter 1).

The parameters to the superclass constructor immediately follow the supertype. This
allows you to pass arguments to the constructor of the superclass of your anonymous
class. If there are multiple constructors to the superclass, you can pass parameters
that are appropriate for any one of those constructors. In this case, the supertype
of your anonymous class is an interface, and the superclass is java.lang.Object.
Therefore, you don't need to pass any arguments to the superclass, and the parentheses
are empty.

By contrast,here is an anonymous class declaration in which the programmer passed
arguments to the constructor:

JButton btn = new JButton("Beep") {
// ...contents omitted
};

In this case,the supertype of the anonymous class is javax.swing.JButton. The
JButton class has several constructors; however, the programmer chose to pass arguments
to the constructor that takes a single String parameter.

One difference between anonymous classes and limited-scope classes is that anonymous
classes cannot use the keywords abstract or final. In fact, every anonymous
class is considered to be final by default. When combined with the fact that these
classes have no name, this means that it is impossible to declare hierarchies of anonymous
classes.

The declaration of the contents of the class follows the parameters to the supertype
constructor:

In the example,you are declaring a class that implements ActionListener, so you
have to override the actionPerformed( ) method in your anonymous class, just as if
you had been writing a normal implementation class. If you want, you can also place
other code within the body. The only thing that you can't place within an anonymous
class is a constructor. In fact, it would be impossible to declare a constructor
because constructors use the name of the class as the method name, and an anonymous
class doesn't have a programmer-accessible type name.

The syntax for anonymous classes is a little weird and is not considered to be mainstream
Java syntax. However, examining how the compiler deals with a declaration
of your anonymous class will help you understand how it works. Here, the compiler
views your anonymous class from Example 6-4:

When the compiler sees an anonymous class declaration, the compiler creates a
unique identifier for the anonymous class and then declares it as a normal method-scoped
inner class.

The identifier that the compiler uses for your anonymous class is the position of the
anonymous class in the order declared in the source file. In the case of the above
example, you know that this anonymous class is the first one declared when reading
from top to bottom in the source file. However, you can never depend on this name,
so you can't reuse the class by instantiating it.

After the name declaration, the compiler adds the inheritance structure for the class.
If ActionListener had been a class instead of an interface, the compiler would have
used the keyword extends instead of implements. Finally, the compiler adds the body
of the anonymous class to the newly declared class.

Once the class is declared, the virtual machine uses the new class in the method:

In this example, the newly declared class is replaced in the source code with the
expansion. Then the addActionListener( ) method line declares a new instance of
this class to pass as a parameter. Although you don't have to know all of these details
to use anonymous classes, it helps to track down bugs and understand the Java compiler - which are both important for hardcore Java programmers.

Problems with Limited-Scope Inner Classes

Since the syntax of anonymous classes is not considered to be mainstream Java syntax,
anonymous classes are difficult to read and are often misunderstood. Furthermore,
they tend to be overused, especially in GUI code. Example 6-7 shows a syntax
that is similar to one I encountered in a GUI for a banking system.

In this single method, the programmer declared no less than four anonymous classes,
all for different reasons. The code in Example 6-7 is a textbook demonstration of
anonymous classes. However, anyone that writes code like this should probably be
beaten to death with a code-readability guide. It's just far too difficult to comprehend
at a glance.

The result achieved by the anonymous classes can be accomplished by implementing
interfaces and proper method calls with much more clarity and maintainability.
For example, the class itself could implement ActionListener and WindowListener to
provide the event handling. Furthermore, the construction of the delayDisplay
would have been easier to read if it had been in a method call instead. Even though
the source code would have been longer,the maintenance situation would be far easier
to understand.

Other limited-scope inner classes suffer from similar readability issues. When you
embed a class declaration inside of a method block, you can easily confuse the reader
and increase the time it takes to integrate new developers into a project.

Additionally, anonymous classes are not reusable at all. This goes against why you
declare a class in the first place. The core of object-oriented programming is reusability;
therefore, declaring a nonreusable class violates the principles of object-oriented
engineering. In many GUIs, I've noticed instances in which programmers declare several
anonymous classes that are nearly identical. Although this will work, it is not
very object-oriented.

Finally, anonymous and other limited-scope inner classes make debugging code difficult
and confusing. You could be stepping through code with a debugger and suddenly
be transported to a piece of code in the middle of a method. It would require
concentration and code awareness to realize that you are in a class declaration. Also,
since anonymous classes don't have programmer-accessible names, errors that occur
in that class are often difficult to locate.

All of these problems make limited-scope inner classes problematic. Therefore,I
advise you to avoid them whenever possible. However,you should now be prepared
when you encounter them in someone else's code. If you have a chance, I would recommend
that you convert their code to use other techniques instead.

In next week's concluding installment to this series on nested classes, excerpted from Hardcore Java, author Robert Simmons will cover static nested classes, double nested classes, and nested classes in interfaces.