CHAPTER 4
Anonymous functions and classes appear in the code itself. They are not declared external to the body of the calling function, but instead are placed inline in the code, and they have no name (hence the term anonymous). They are often used to define a functionality or a class that is only required once at a point in the code. In order to use an anonymous class, we must implement an interface or extend an existing class. An anonymous class is a child class; it is an unnamed derived class that implements or extends the functionality of a parent class. We will see extensive use of anonymous classes in the event handling of the calculator application in Chapter 7.
Code Listing 4.0: Anonymous Inner Class vs. Class Instance
public class MainClass { // Parent class static class OutputLyrics { public void output() { System.out.println("No lyrics supplied..."); } }
public static void main(String[] args) {
// Create a normal instance from the OutputLyrics class. OutputLyrics regularInstance = new OutputLyrics();
// Anonymous Inner Class OutputLyrics anonymousClass = new OutputLyrics() { public void output() { System.out.println( "Desmond has a barrow in the market place."); } };
// Call the output methods: regularInstance.output();
// And using the anonymous class: anonymousClass.output(); } } |
Code Listing 4.0 shows a basic example of an anonymous inner class. First, we define a parent class, which is called OutputLyrics. The class contains a single method that prints a string of text to the screen called output. Inside the main method, we create an instance of the OutputLyrics class. Note that the section marked with the comment “// Anonymous Inner Class” in the next line is important—we define and declare a new class that derives from the OutputLyrics class and that defines its own output method. Notice that we are creating an instance from a class that derives from OutputLyrics. The instance is called anonymousClass, but the class itself has no name. The syntax for an anonymous class is the same as the syntax for creating an instance from an existing parent class, except that the definition is followed immediately by a code block that defines the child class. Code Listing 4.1 shows the important lines from Code Listing 4.0.
Code Listing 4.1: Anonymous Class
// Anonymous Inner Class OutputLyrics anonymousClass = new OutputLyrics() { public void output() { System.out.println( "Desmond has a barrow in the market place."); } }; |
Notice the first line in Code Listing 4.1 does not end with a semicolon, as a typical object definition would. Instead, we open a code block and override the output method. Declaring an anonymous inner class in this manner is a statement, and the semicolon actually comes at the end, after the code block is closed.
When we call the output method of our regularInstance, the program will print “No lyrics supplied…” to the output. This is the normal behavior of an OutputLyrics object. However, when we call the output method of our anonymous class, it will output the lyrics “Desmond has a barrow in the market place.”
The example in Code Listing 4.0 was trivial—it showed the basic syntax for using an anonymous class, but it is not a good example of why we would use this mechanism. Anonymous classes are often used when we need to pass functionality as a parameter to a method. For instance, if we know that we want to perform some operation between two integers and return some result, we could use an anonymous class that derives from the operation class, as per Code Listing 4.2.
Code Listing 4.2: Using Anonymous Inner Classes as Parameters
public class MainClass { // Parent class static class MathOperation { public int operation(int a, int b) { return 0; } } // Method that takes an object of MathOperation as a parameter. static int performOperation(int a, int b, MathOperation op) { return op.operation(a, b); } public static void main(String[] args) { // Some variables int x = 100; int y = 97; // Call the PerformOperation function with addition: int resultOfAddition = performOperation(x, y, // Anonymous inner class used as a parameter. new MathOperation() { public int operation(int a, int b) { return a + b; } });
// Call the PerformOperation function with subtraction: int resultOfSubtraction = performOperation(x, y, // Anonymous inner class used as a parameter. new MathOperation() { public int operation(int a, int b) { return a - b; } }); // Output Addition: 197 System.out.println("Addition: " + resultOfAddition); // Output Subtraction: 3 System.out.println("Subtraction: " + resultOfSubtraction); } } |
In Code Listing 4.2, we create a parent class called MathOperation. The class has a single method that takes two int parameters and returns some result. We also define a static method called performOperation that takes two int parameters and an instance of the MathOperation. The fact that the performOperation method takes a MathOperation as a parameter is the main concept in this illustration.
In the main method, we create two variables—resultOfAddition and resultOfSubtraction. The variables are defined as being the result from a call to performOperation, and two integer parameters, x and y, are passed. However, the crucial part is the third parameter to these calls to performOperation (highlighted in yellow in Code Listing 4.3).
Code Listing 4.3: MathOperation Anonymous Class
int resultOfAddition = performOperation(x, y, // Anonymous inner class used as a parameter. new MathOperation() { public int operation(int a, int b) { return a + b; } }); |
The third parameter is an anonymous inner class. Instead of passing an instance of the MathOperation class, we derive and define an instance of an anonymous class. We are passing an instance of the anonymous child class to the performOperation method as a parameter. This child class has no name, and the instance of it has no name, either. We can still pass it as a parameter to the performOperation function. Inside the performOperation method, the instance is called op, but the caller does not need to create or name the instance—it is created and passed as a parameter when and where it is needed.
The previous examples used a class as the parent for our anonymous inner classes. However, the parent class is often abstract or an interface. In Code Listing 4.3, when we use the child classes to call a single method, called operation, what are really doing is passing functionality to the performOperation class. In our example, we defined the MathOperation class as a normal class, but it might be more useful to define it as an interface (or perhaps an abstract class). The class has only a single method, and it makes little sense to perform an operation when we do not know what the operation is. Code Listing 4.4 shows the same example, except that the MathOperation class has been declared as an interface rather than a class.
Code Listing 4.4: Using an Interface as the Parent Class
public class MainClass { // Parent interface interface MathOperation { public int operation(int a, int b); } // Method that takes an object of MathOperation as a parameter. static int performOperation(int a, int b, MathOperation op) { return op.operation(a, b); } public static void main(String[] args) { // Some variables int x = 100; int y = 97; // Call the PerformOperation function with addition: int resultOfAddition = performOperation(x, y, // Anonymous inner class used as a parameter. new MathOperation() { public int operation(int a, int b) { return a + b; } });
// Call the PerformOperation function with subtraction: int resultOfSubtraction = performOperation(x, y, // Anonymous inner class used as a parameter. new MathOperation() { public int operation(int a, int b) { return a - b; } }); // Output Addition: 197 System.out.println("Addition: " + resultOfAddition); // Output Subtraction: 3 System.out.println("Subtraction: " + resultOfSubtraction); } } |
In Code Listing 4.4, the relevant changes are highlighted in yellow. Interfaces consist solely of abstract methods, so there is no longer a body for the operation method defined in the MathOperation interface.
The examples we have seen so far show the basic syntax of an anonymous inner class—they do not illustrate the most common usage of this mechanism. Inner classes are most commonly used to provide functionality for callbacks in event-driven GUI programming. We will see extensive use of inner classes in the section on GUI events in Chapter 7. The basic objective is to save code. We do not need to declare a class and create an instance to state what should occur when the user clicks a mouse or presses a key at the keyboard. Instead, we declare and define an anonymous inner class that specifies the action to be undertaken when these events occur. This makes our code easier to read, and shorter, because we define the functionality at the point where we need it (i.e. where the event is being created) instead of defining the functionality in some external class.