Using Inner Classes
In this chapter, you find out how to use three advanced types of classes: inner classes, static inner classes, and anonymous inner classes. All three are useful in certain circumstances. In particular, inner classes and anonymous inner classes are commonly used with graphical applications created with Swing. For more information about Swing, refer to Book VI. In this chapter, I just concentrate on the mechanics of creating these types of classes.
TECHNICAL STAUFF Once again, this chapter could have a Technical Stuff icon pasted next to every other paragraph. The immediate usefulness of some of the information I present in this chapter may seem questionable. But trust me-you need to know this stuff when you start writing Swing applications. If you want to skip this chapter for now, that's okay. You can always come back to it when you're learning Swing and you need to know how inner classes and anonymous inner classes work.
Declaring Inner Classes
An inner class is a class that's declared inside of another class. Thus the basic structure for creating an inner class is as follows:
class outerClassName
{
private class innerClassName
{
// body of inner class
}
}
The class that contains the inner class is called an outer class. You can use a visibility modifier with the inner class to specify whether the class should be public, protected, or private. This visibility determines whether other classes can see the inner class.
Understanding inner classes
At the surface, an inner class is simply a class that's contained inside another class. However, there's more to it than that. Here are some key points about inner classes:
An inner class automatically has access to all the fields and methods of the outer class-even private fields and methods. Thus an inner class has more access to its outer class than a subclass has to its super-class. (A subclass can access public and protected members of its superclass, but not private members.)
An inner class carries with it a reference to the current instance of the outer class that enables it to access instance data for the outer class.
Because of the outer class instance reference, you can't create or refer to an inner class from a static method of the outer class. You can, however, create a static inner class, as I describe in the section "Using Static Inner Classes" later in this chapter.
Tip One of the main reasons for creating an inner class is to create a class that's only of interest to the outer class. As a result, you usually declare inner classes to be private so other classes can't access them.
Occasionally, code in an inner class needs to refer to the instance of its outer class. To do that, you list the name of the outer class followed by the dot operator and this. For example, if the outer class is named MyOuterClass, you would use MyOuterClass.this to refer to the instance of the outer class.
An example
Book III, Chapter 5 introduces an application that uses the Timer class in the Swing package (javax.swing.Timer) that displays the lines Tick… and Tock… on the console at a one-second interval. It uses a class named Ticker that implements the ActionListener interface to handle the Timer object's clock events.
Tip In this chapter, you see a total of three different versions of this application. You may want to quickly review Book III, Chapter 5 if you're unclear on how this application uses the Timer class to display the Tick… and Tock… messages, or why the JOptionPane dialog box is required.
Listing 7-1 shows a version of this application that implements the Ticker class as an inner class.
Listing 7-1: Tick Tock with an Inner Class
import java.awt.event.*;
import javax.swing.*;
public class TickTockInner
{
private String tickMessage = "Tick..."; → 6
private String tockMessage = "Tock..."; → 7
public static void main(String[] args)
{
TickTockInner t = new TickTockInner(); → 11
t.go(); → 12
}
private void go() → 15
{
// create a timer that calls the Ticker class
// at one second intervals
Timer t = new Timer(1000, new Ticker()); → 19
t.start();
// display a message box to prevent the
// program from ending immediately
JOptionPane.showMessageDialog(null, → 24
"Click OK to exit program");
System.exit(0); → 26
}
class Ticker implements ActionListener → 29
{
private boolean tick = true;
public void actionPerformed(ActionEvent event) → 33
{
if (tick)
{
System.out.println(tickMessage); → 37
}
else
{
System.out.println(tockMessage); → 41
}
tick = !tick;
}
}
}
The Observer pattern
Event listeners in Java are part of a Java model called the Delegation Event Model. The Delegation Event Model is an implementation of a more general design pattern called the Observer pattern. This pattern is useful when you need to create objects that interact with each other when a change in the status of one of the objects occurs. The object whose changes are being monitored is called the observable object, and the object that monitors those changes is called the observer object.
The observer object registers itself with the observable object, which then notifies the observer object when its status changes.
You discover more about how Java implements this pattern for event handling in Book VI. But if you're interested, you may want to investigate the Observer and Observable interfaces that are a part of the Java API. They provide a standard way to create simple implementations of the Observer pattern.
The following paragraphs describe some of the highlights of this program:
→ 6
The String variables named tickMessage and tockMessage (line 7) contain the messages to be printed on the console. Note that these variables are defined as fields of the outer class. As you'll see, the inner class Ticker is able to directly access these fields.
→ 11
Because an inner class can only be used by an instantiated object, you can't use it directly from the static main method. As a result, the main method in this program simply creates an instance of the application class (TickTockInner).
→ 12
This line executes the go method of the new instance of the TickTockInner class.
Tip The technique used in lines 11 and 12 is a fairly common programming technique that lets an application quickly get out of a static context and into an object-oriented mode.
Open table as spreadsheet
→ 15
The go method, called from line 12.
→ 19
This line creates an instance of the Timer class with the timer interval set to 1,000 milliseconds (1 second) and the ActionListener set to a new instance of the inner class named Ticker.
→ 24
Here the JOptionPane class is used to display a dialog box. This dialog box is necessary to give the timer a chance to run. The application ends when the user clicks OK.
→ 26
This line calls the exit method of the System class, which immediately shuts down the Java Virtual Machine. This method call isn't strictly required here, but if you leave it out, the timer continues to run for a few seconds after you click OK before the JVM figures out that it should kill the timer.
→ 29
This line is the declaration for the inner class named Ticker. Note that this class implements the ActionListener interface.
→ 33
The actionPerformed method is called by the Timer object every 1,000 milliseconds.
→ 37
In this line and in line 41, the inner class directly accesses a field of the outer class.