0% found this document useful (0 votes)
86 views24 pages

Java Anonymous Classes

This lesson will explain anonymous classes. Anonymous classes are essentially Local Classes without a name. Nested top-level classes and interfaces are the next lesson in the series.

Uploaded by

api-3836483
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
86 views24 pages

Java Anonymous Classes

This lesson will explain anonymous classes. Anonymous classes are essentially Local Classes without a name. Nested top-level classes and interfaces are the next lesson in the series.

Uploaded by

api-3836483
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
You are on page 1/ 24

Preface

This series of lessons is designed to teach you about the essence of Object-Oriented Programming
(OOP) using Java.

The first lesson in the series was entitled The Essence of OOP Using Java, Objects, and
Encapsulation. The previous lesson was entitled The Essence of OOP using Java, Local Classes.

You may find it useful to open another copy of this lesson in a separate browser window. That will
make it easier for you to scroll back and forth among the different figures and listings while you are
reading about them.

For further reading, see my extensive collection of online Java tutorials at Gamelan.com. A
consolidated index is available at www.DickBaldwin.com.

Preview

What can you include in a class definition?

There are several different kinds of items that can be included in a class definition. As you learned in
the earlier lessons in this series, the list includes:

• Static variables
• Instance variables
• Static methods
• Instance methods
• Constructors
• Static initializer blocks
• Instance initializers

Can also contain other class definitions

As you also learned in previous lessons, a class definition can also contain the following four kinds of
inner classes:

• Member classes
• Local classes
• Anonymous classes
• Nested top-level classes and interfaces

The previous two lessons explained member classes and local classes. This lesson will explain
anonymous classes. The next lesson will explain nested top-level classes and interfaces.

(Note that it is questionable whether a nested top-level class or interface should be referred to as an
inner class, because an object of a nested top-level class can exist in the absence of an object of the
enclosing class. Regardless of whether the term inner class applies, a nested top-level class is
defined within the definition of another class, so its definition is internal to the definition of another
class.)
What is an anonymous class?

I'm going to begin my discussion with a quotation from one of my favorite authors, David Flanagan,
author of Java in a Nutshell.

"An anonymous class is essentially a local class without a name."

If you have read the previous lesson, you should know quite a lot about local classes at this point in
time. Continuing with Flanagan's words,

"Instead of defining a local class and then instantiating it, you can often use an anonymous class to
combine these two steps... an anonymous class is defined by a Java expression, not a Java
statement. This means that an anonymous class definition can be included within a larger Java
expression..."

As you will see from the sample program in this lesson, anonymous class definitions are often
included as arguments to method calls.

As is the case for an object of a member class or a local class (discussed in previous lessons), an
object of an anonymous class must be internally linked to an object of the enclosing class.

Thus, an anonymous class is truly an inner class, because an object of the anonymous class cannot
exist in the absence of an object of the enclosing class.

What about an anonymous interface?

Interfaces defined within classes are implicitly static. This means that they are always top-level.
There is no such thing as a member interface, a local interface, or an anonymous interface.

Why use anonymous classes?

As with local classes, objects instantiated from anonymous classes share many of the characteristics
of objects instantiated from member classes. However, in some cases, an anonymous class can be
defined closer to its point of use than would be possible with a member class or a local class. Once
you become accustomed to the somewhat cryptic syntax used with anonymous classes, this can often
lead to improved code readability.

Probably the most important benefit of anonymous classes has to do with accessing the members of
enclosing classes. Just like with member classes and local classes, methods of an anonymous class
have direct access to all the members of the enclosing classes, including private members. Thus the
use of anonymous classes can often eliminate the requirement to connect objects together via
constructor parameters.

In addition, although not demonstrated in this lesson, as with local classes, objects of anonymous
classes have access to final local variables that are declared within the scope of the anonymous class.

Can be particularly useful when ...

An anonymous class can be particularly useful in those cases where


• There is no reason for an object of the anonymous class to exist in the absence of an object of
the enclosing class.
• There is no reason for an object of the anonymous class to exist outside a method of the
enclosing class.
• Methods of the object of the anonymous class need access to members of the object of the
enclosing class.
• Methods of the object of the anonymous class need access to final local variables and method
parameters belonging to the method in which the anonymous class is defined.
• Only one instance of the anonymous class is needed.
• There is no need for the class to have a name that is accessible elsewhere in the program.

Purpose of this lesson

This lesson explains anonymous classes from a practical viewpoint, including a comparison between
anonymous classes and local classes.

Anonymous classes versus local classes

Once again, according to David Flanagan,

"...an anonymous class behaves just like a local class, and is distinguished from a local class merely
in the syntax used to define and instantiate it."

Unlike a local class, however, an anonymous class cannot define a constructor. An anonymous class
can define an instance initializer, which can provide some of the benefits of a constructor.

(I discussed instance initializers in detail in an earlier lesson entitled The Essence of OOP using
Java, Instance Initializers. As you may recall, a primary shortcoming of an instance initializer as
compared to a constructor is that an instance initializer cannot accept incoming parameters.)

Restrictions on the use of anonymous classes

Because an anonymous class has no name, and the definition and instantiation of the class appear in a
single expression, only one instance of each anonymous class can be created. If you need more than
one instance of the class, you should probably use a local class, a member class, or a top-level class
instead.

As mentioned above, it is not possible to define constructors for anonymous classes. If you need to
use a constructor when you instantiate the class, you should probably use a local class, a member
class, or a top-level class instead.

As with member classes and local classes, anonymous classes cannot contain static members.

As with local variables and local classes, anonymous classes cannot be declared public, protected,
private, or static. In fact, no modifiers can be specified in the definition of an anonymous class.

Smoke and mirrors


As I told you in my earlier lessons on local classes, the methods in an anonymous class don't really
have access to local variables and method parameters. Rather, when an object of the anonymous
class is instantiated, copies of the final local variables and method parameters referred to by the
object's methods are stored as instance variables in the object. The methods in the object of the
anonymous class really access those hidden instance variables.

Thus, the local variables and method parameters accessed by the methods of the local class must be
declared final to prevent their values from changing after the object is instantiated.

There are some additional activities involving smoke and mirrors taking place behind the scenes
when you define and instantiate an anonymous class. Generally speaking, this involves the automatic
generation of code to cause things to behave as they do. The good news is that you don't have to
write that extra code, and you don't have to maintain it. The extra code is written for you, and if you
modify your class structure, the extra code is automatically modified accordingly.

You can read about the code that is automatically generated in my earlier lessons on local classes and
member classes.

Syntax for anonymous classes

Before getting into actual code in the sample program, I want to explain the syntax used to define and
instantiate an anonymous class.

The definition and instantiation of an anonymous class uses one or the other of the two expressions
shown in Figure 1.

new className(optional argument list){classBody}

new interfaceName(){classBody}
Figure 1

Usually, this expression is included inside a larger overall expression, such as an argument to a
method call.

What does the first expression mean?

Here is how I usually explain this syntax to my students. The first expression in Figure 1 starts out
fairly normal, but becomes cryptic very quickly. This expression instantiates a new object from an
unnamed and previously undefined class, which automatically extends the class named className,
and which cannot explicitly implement any interfaces. The body of the new class is given by
classBody.

The result of executing this expression is that a new class that extends className is defined, a new
object of the new class is instantiated, and the expression is replaced by a reference to the new object.

Example usage

If this expression appears as the right operand of an assignment operator, the object's reference is
saved in the left operand of the assignment operator. If the expression appears as an argument in a
method call, the object's reference is passed to the method. If the expression appears in some other
form of larger overall expression, the object's reference is handed over to the surrounding expression
to be used appropriately.

What about instantiating an interface?

The second expression in Figure 1 starts out weird. To my knowledge, there is no other situation in
Java where you apply the new operator to the name of an interface. From the beginning, you have
been told that you cannot instantiate an object of an interface. (An interface is implicitly abstract and
it doesn't have a constructor, not even a default constructor.) However, you can instantiate an object
of a class that implements none, one, or more interfaces.

The correct interpretation of the second expression in Figure 1 is as follows. This expression
instantiates a new object from an unnamed and previously undefined class, which automatically
implements the interface named interfaceName, and automatically extends the class named Object.
The class can explicitly implement one, and only one interface, and cannot extend any class other
than Object. Once again, the body of the new class is given by classBody.

As in the case of the first expression in Figure 1, the result of executing this expression is that a new
class that implements interfaceName is defined, a new object of the new class is instantiated, and the
expression is replaced by a reference to the new object. That reference is handed over to the
surrounding expression to be used appropriately.

What about constructor parameters?

As mentioned earlier in this lesson, since the new class doesn't have a name, it isn't possible to define
a constructor for the new class. According to Flanagan,
"Any arguments you specify between the parentheses following the superclass name in an anonymous
class definition are implicitly passed to the superclass constructor."
Thus, it is possible to define an anonymous class that extends a class whose constructor requires
parameters, and to pass those parameters to the superclass constructor when the anonymous class is
instantiated.

The parentheses following interfaceName in the second expression in Figure 1 must always be
empty. In this case, the superclass is always Object, which never expects constructor parameters.

Enough talk, let's see some code

The paragraphs that follow will explain a program named InnerClasses08, which is designed
specifically to illustrate anonymous classes, and to compare anonymous classes with local classes. I
will discuss the program in fragments. A complete listing of the program is provided in Listing 10
near the end of the lesson.

Discussion and Sample Code

When the program is executed, it produces the GUI shown in Figure 2. I will refer back to this figure
during the discussion of the program.
Figure 2 Program GUI

Class file names

This program consists of a total of six classes:

• Two top-level classes


• One local class
• Three anonymous classes

When compiled, the program produces the class files shown in Figure 3.

GUI$1$BaldButton.class
GUI$1.class
GUI$2.class
GUI$3.class
GUI.class
InnerClasses08.class
Figure 3

As you will see later, the file named GUI$1$BaldButton.class represents the local class. The three
files named GUI$1.class, GUI$2.class, and GUI$3.class represent anonymous classes. The two
remaining files represent top-level classes.
(As you can see, the anonymous classes are not truly anonymous, since the files that represent them
must have names. Generally, however, the establishment of the individual names is beyond the
control of the programmer, and the names are not known to the program in a way that makes it
possible to refer to them by name.)
Program structure and behavior

This program is designed to illustrate the use of local classes and anonymous classes in a very
practical way. It illustrates one implementation of a local class and three different implementations of
anonymous classes. The program compares the local class with an anonymous class designed to
accomplish the same purpose. The program also illustrates the use of instance initializers as an
alternative to constructors.

A local class

The program defines and uses a local class to instantiate an object to handle mouse clicked events on
a button with low-level event handling. This class uses a constructor to enable mouse events on a new
extended Button class. It also uses a constructor to display the name of the class file.

An anonymous class to compare with the local class

The program also defines and uses an anonymous class to instantiate an object to handle mouse
clicked events on a button with low-level event handling. This class uses an instance initializer to
enable mouse events on a new extended Button class. It also uses an instance initializer to display the
name of the class file. This class and the local class described above provide a direct comparison
between the use of local classes and anonymous classes to serve the same purpose.

An anonymous class that implements an interface

The program illustrates the use of an anonymous class, which implements the MouseListener
interface, to instantiate an object to handle mouse clicked events using the source-listener event
model (sometimes referred to as the delegation event model or the JavaBeans event model). The
anonymous class uses an instance initializer to display the name of the class file.

An anonymous class that extends an existing class

The program illustrates the use of an anonymous class, which extends the WindowAdapter class, to
instantiate an object to handle window events fired by the close button in the upper-right corner of the
Frame object shown in Figure 2. This class also uses the source-listener event model, and uses an
instance initializer to display the name of the class file.

The screen output

The program produces the screen output shown in Figure 4 when

• The program is started


• Each button shown in Figure 2 is clicked once in succession, going from left to right
• The close button in the upper-right corner of the Frame object in Figure 2 is clicked

Local class name: GUI$1$BaldButton


Anonymous class B name: GUI$1
Anonymous class C name: GUI$2
Anonymous window listener class name: GUI$3
buttonA clicked
buttonB clicked
buttonC clicked
Close button clicked
Figure 4

When the close button is clicked, the program produces the last line of text in Figure 4 and
terminates.

I will identify the code that produces each line of output text in the discussion of the program that
follows.

The controlling class

The controlling class for the program is shown in Listing 1.


public class InnerClasses08 {
public static void main(String[] args){
new GUI();
}//end main
}//end class InnerClasses08

Listing 1

As you can see, the controlling class is very simple, with the main method instantiating an object of
the GUI class. This results in the GUI that is pictured in Figure 2.

Local and anonymous classes inside GUI constructor

The local class and the three anonymous classes are defined inside the constructor for the GUI class.
(Recall that local classes and anonymous classes are defined inside code blocks, which often place
them inside methods and constructors, but you can also place them inside static initializer blocks and
instance initializers.)
The first four lines of the output text in Figure 4 are produced by constructors and instance initializers
in the local and anonymous classes. Therefore, those four lines of text are produced when the new
object of the GUI class is instantiated.

The GUI class

As is often the case, the GUI class used to create the visual GUI shown in Figure 2 consists solely of
a constructor. Basically, this constructor places three buttons in the frame and registers event
handlers on the buttons and on the frame. Once the GUI object is constructed and appears on the
screen, all further activity in the program occurs under control of the event handlers associated with
the buttons and the frame.
(You can learn more about event handling by reviewing my online tutorial lessons at
http://www.dickbaldwin.com/tocmed.htm.)
The GUI constructor

The GUI class, and the constructor for that class begin in Listing 2.
class GUI extends Frame{
public GUI(){//constructor
setLayout(new FlowLayout());
setSize(250,75);
setTitle("Copyright 2003 R.G.Baldwin");

Listing 2

As you can see, the GUI class extends Frame, so that an object of the class is a frame.

The constructor code shown in Listing 2 simply sets values for the layout, size, and title properties of
the frame.

The BaldButton class

The BaldButton class, whose definition begins in Listing 3, is a local class that extends Button.
This class extends the Button class to make it possible to override the processMouseEvent method
in order to handle mouse events that are fired by the button. This is a form of low-level event
handling, which will be contrasted with source-listener event handling later in the program.

Listing 3 shows the constructor for the BaldButton class.


class BaldButton extends Button{
BaldButton(String text){//constructor
enableEvents(AWTEvent.MOUSE_EVENT_MASK);
setLabel(text);
System.out.println("Local class name: " +
getClass().getName());
}//end constructor

Listing 3

Enable mouse events

The most important code in the constructor is the statement that enables mouse events on the button.
If you are unfamiliar with the enableEvents method, you should look it up in the Sun documentation.

Briefly, this method must be invoked on the button to cause the overridden processMouseEvent
method to be invoked later when the button fires a mouse event.

The remaining constructor code

The remaining code in the constructor

• Sets the text value on the face of the button


• Gets and displays the name of the class file that represents this local class

The screen output

Construction of the button by the code in Listing 3 causes the text shown in Figure 5 to appear on the
screen. This is how I was able to identify the name of the class file that represents the local class in
my earlier discussion of class file names.

Local class name: GUI$1$BaldButton


Figure 5

We will see later that this button will be added as the leftmost button in the GUI shown in Figure 2.

The processMouseEvent method

Continuing with the constructor for the BaldButton class, Listing 4 shows the overridden
processMouseEvent method for an object of the BaldButton class.
public void processMouseEvent(
MouseEvent e){
if (e.getID() ==
MouseEvent.MOUSE_CLICKED){
System.out.println("buttonA clicked");
}//end if

//The following is required of overridden


// processMouseEvent method.
super.processMouseEvent(e);
}//end processMouseEvent
}//end class BaldButton

//Add button to Frame


add(new BaldButton("A"));
Listing 4

This method is invoked each time an object instantiated from this class fires a mouse event. That is
why I refer to the method as an event handler for the button.

Different kinds of mouse events

A button can fire a variety of different kinds or subcategories of mouse events:

• MOUSE_CLICKED
• MOUSE_DRAGGED
• MOUSE_ENTERED
• MOUSE_EXITED
• MOUSE_MOVED
• MOUSE_PRESSED
• MOUSE_RELEASED

In this case, I elected to ignore all but MOUSE_CLICKED. This subcategory of mouse event occurs
when a mouse button is pressed and then released.

Thus the code in the event handler of Listing 4 first confirms that the event was of the
MOUSE_CLICKED variety, and if so, it displays a message that matches the fifth line of text in the
output shown in Figure 4.

Invoke processMouseEvent on the superclass

Without getting into the details of why this is required, I'm simply going to tell you that when you use
this low-level event model to handle events, your overridden processMouseEvent method must call
the same method in the superclass, passing the incoming parameter of type MouseEvent as a
parameter to the superclass version of the method.

Add a button to the frame

The last statement in Listing 4 instantiates a new BaldButton object, setting the text on the face of
the button to A, and adds that new object to the frame. Because the layout property of the frame has
been set to FlowLayout, and because this is the first component added to the frame, this button
appears as the leftmost button in the GUI shown in Figure 2.

Could instantiate multiple buttons of this type

Although I instantiated the button object as an anonymous object in this case, that wasn't necessary.
Using this local class, I could instantiate more than one object of this type, saving the object's
references in reference variables of the appropriate type. Later we will see that this is not possible for
anonymous classes.

It is interesting to note, however, that with this event handle model, if I were to instantiate multiple
buttons of this type, the same processMouseEvent method would be invoked no matter which of the
buttons fired a mouse event. If I wanted different behavior as a result of the different buttons firing
mouse events, I would have to write code inside the processMouseEvent method to deal with that
issue. The source-listener event model that I will illustrate later doesn't suffer from that restriction.

An anonymous inner class for low-level event handling

Listing 5 shows the beginning of an anonymous class to perform low-level event handling similar to
that shown in Listing 4. This code defines an anonymous inner class, which extends Button, and
which has mouse events enabled. I provided this class primarily for comparison with the local class
named BaldButton. This class is an anonymous alternative to the local BaldButton class.
add(new Button("B")
{//Begin class definition
{//Instance initializer
enableEvents(
AWTEvent.MOUSE_EVENT_MASK);
System.out.println(
"Anonymous class B name: " +
getClass().getName());
}//end instance initializer

Listing 5

An argument to the add method

Note that the definition of this anonymous class appears as an argument to the add method for the
frame. Thus, the anonymous object instantiated from the anonymous class is added as the second
(middle) button in Figure 2.

Extends the Button class

Note also that this form of anonymous class implicitly extends the Button class. Once again, this
makes it possible to override the processMouseEvent method belonging to the Button class.

An instance initializer

As I mentioned earlier in this lesson, it is not possible to define a constructor for an anonymous
class. However, it is possible to define an instance initializer. This class defines an instance
initializer, which

• Enables mouse events on an anonymous object instantiated from the anonymous class
• Gets and displays the name of the class file that represents the anonymous class

The screen output

Therefore, the instantiation of this anonymous object causes the text shown in Figure 6 to appear on
the screen. About all you can tell by looking at this class name is that it is the name of a file that
represents an anonymous class.

Anonymous class B name: GUI$1


Figure 6

Overridden processMouseEvent method

The remaining code in the anonymous class definition is shown in Listing 6.


public void processMouseEvent(
MouseEvent e){
if (e.getID() ==
MouseEvent.MOUSE_CLICKED){
System.out.println(
"buttonB clicked");
}//end if

//Required of overridden
// processMouseEvent method.
super.processMouseEvent(e);
}//end processMouseEvent
}//end class definition
);//end add method call

Listing 6

Basically, the remaining code consists of an overridden processMouseEvent method, and the curly
braces, parentheses, and semicolon necessary to complete the expression and the statement.

Same code as before

The code in this overridden processMouseEvent method is essentially the same as that shown for the
local class in Listing 4, except that it produces a different message on the screen when the user clicks
the button.

Clicking the middle button in Figure 2 produces the screen output shown by the sixth line in Figure 4.

Implementing a listener interface


Now I'm going to switch from low-level event handling to source-listener event handling. With this
event handling model

• A listener object is instantiated from a class that implements a specific listener interface. In
this case, that interface will be the MouseListener interface.
• The listener object is registered on an object that knows how to fire events of a type that is
associated with the listener interface. In this case, that will be events of type MouseEvent.
• When the source object fires an event of the specified type, one of the methods belonging to
the registered listener object will be invoked to handle the event. The different methods
belonging to the listener object are declared in the implemented listener interface.

Instantiating and registering a MouseListener object

The code to accomplish this begins in Listing 7. Listing 7 begins by instantiating a new Button
object.
(Note that with this event model, it is not necessary to extend the Button class, because it is not
necessary to override methods belonging to the Button object.)
After instantiating a new Button object, the code in Listing 7 invokes the addMouseListener
method to register a MouseListener object on that button. The argument to the addMouseListener
method must be a reference to an object instantiated from a class that implements the MouseListener
interface.
Button buttonC = new Button("C");

buttonC.addMouseListener(new MouseListener()
{//begin class definition
//Instance initializer
{System.out.println(
"Anonymous class C name: " +
getClass().getName());}

Listing 7

Instantiate the listener object

In this case, that listener object is created by writing an expression to instantiate an anonymous object
from an anonymous class and placing that expression as an argument to the addMouseListener
method.

Implement the MouseListener interface

The definition of the anonymous class in this example uses the syntax that implements an interface.

An instance initializer

As before, an instance initializer is used to get and display the name of the class file that represents
the anonymous class. Thus, when the new anonymous object of the anonymous class is instantiated,
the text shown in Figure 7 appears on the screen. Note the similarity of this class file name to that
shown earlier in Figure 6. The names of the two class files differ only with respect to a number that
is provided by the compiler to guarantee that each class file name is unique.
Anonymous class C name: GUI$2
Figure 7

Implementing the interface

Whenever a class implements an interface, it must provide a concrete definition for each of the
methods declared in the interface, even if some of those methods are empty.

Continuing with the definition of the anonymous class, Listing 8 provides definitions for all five of
the methods declared in the MouseListener interface. Four of those methods are defined as empty
methods.
public void mouseClicked(MouseEvent e){
System.out.println("buttonC clicked");
}//end mouseClicked

//All interface methods must be defined


public void mousePressed(MouseEvent e){}
public void mouseReleased(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}

}//end class definition


);//end addMouseListener call

add(buttonC);//add button to frame

Listing 8

Separation of event subcategories

One of the major differences between the low-level event model discussed earlier and the source-
listener model being discussed here has to do with where the separation between the different
subcategories (mouseClicked, mousePressed, mouseReleased, etc.) of a given event type is
accomplished

In the low-level model, the separation must be accomplished by code in the overridden event handler
method, such as with the if statement in the processMouseEvent method defined in Listing 6.

In the source-listener model, the separation is accomplished before the event handler method is
invoked, and a specific event handler method, such as the mouseClicked method is invoked on the
listener object.

When the button fires a mouse event ...

In this case, whenever the button fires a MouseEvent of the mouseClicked subcategory, the
mouseClicked method defined in Listing 8 will be invoked, causing the seventh line of text in Figure
4 to appear on the screen.

Whenever the button fires a MouseEvent of one of the other subcategories, one of the empty
methods defined in Listing 8 will be invoked. This method will return immediately, doing nothing
but wasting a little computer time.
(In case you are wondering what happened to the mouseMoved and mouseDragged methods, they
are defined in the MouseMotionListener interface instead of the MouseListener interface.)
Add the button to the frame

Finally, the last statement in Listing 8 adds the new button to the frame as the rightmost button in
Figure 2.

A disclaimer

I wrote this code the way that I did in Listing 8 to illustrate an anonymous class that implements an
interface. In real life, I would probably cause the anonymous class to extend the MouseAdapter
class and override the mouseClicked method instead of implementing the MouseListener interface.
That would eliminate the requirement for me to define the four empty methods in Listing 8.

Extending the WindowAdapter class

The above disclaimer provides a perfect lead-in to the definition of the anonymous class shown in
Listing 9.
addWindowListener(new WindowAdapter()
{//begin class definition
//Instance initializer
{System.out.println(
"Anonymous window listener class " +
"name: " + getClass().getName());}

public void windowClosing(WindowEvent e){


System.out.println(
"Close button clicked");
System.exit(0);
}//end windowClosing
}//end class definition
);//end addWindowListener

setVisible(true);

}//end constructor
}//end GUI class

Listing 9

Registering a WindowListener on the frame

The code in Listing 9 instantiates an anonymous object of an anonymous class, which extends the
WindowAdapter class. That anonymous object is registered as a WindowListener on the frame by
passing the object's reference to the addWindowListener method belonging to the frame.
(The addWindowListener method requires an incoming parameter of type WindowListener. This is
satisfied by the fact that the WindowAdapter class implements the WindowListener interface. Thus,
an object instantiated from a class that extends WindowAdapter can also be treated as type
WindowListener.)
The screen output

This anonymous class definition uses an instance initializer to get and display the name of the class
that represents the anonymous class. Thus, when the anonymous object of the anonymous class is
instantiated, the text shown in Figure 8 appears on the screen.

Anonymous window listener class name: GUI$3


Figure 8

Class file names

In an earlier lesson explaining member classes, I told you that it is possible to examine the names of
the class files that represent the member classes and to determine quite a lot about the structure of the
program in terms of which classes are members of which other classes. However, in the case of local
classes and anonymous classes, about all that you can determine from the name of the class file is that
the file either represents a local class or represents an anonymous class (see the summary of class
named in Figure 3).

The windowClosing method

The code in Listing 9 overrides the windowClosing method inherited from the WindowAdapter
class.

Clicking the close button with the X in the upper right hand corner of Figure 2 causes the
windowClosing method to be invoked on any WindowListener objects that have been registered on
the frame. In this case, the overridden windowClosing method in Listing 9 cases the last line of text
in Figure 4 to be displayed on the screen.

Following that, the overridden windowClosing method invokes the System.exit method to terminate
the program.

The remaining code

The remaining code in Listing 9

• Causes the frame to become visible


• Signals the end of the constructor
• Signals the end of the GUI class

The GUI remains on the screen until terminated

Once the constructor is executed, the GUI simply remains on the screen waiting for someone to click
one of the buttons or to click the close button in the upper right corner of the frame. When these
buttons are clicked, the event handlers are invoked, causing text such as that shown in Figure 9 to
appear on the screen.

buttonA clicked
buttonB clicked
buttonC clicked
Close button clicked
Figure 9

Simple event handlers

In this demo program, the event handlers simply display messages on the screen, and in the case of
the close button, terminate the program. In a real world program, the behavior of the event handlers
would likely be much more substantive, but the overall skeleton of the program need not be any
different from that illustrated here.

Run the Program

At this point, you may find it useful to compile and run the program shown in Listing 10 near the end
of the lesson.

Summary

In addition to a number of other items, a class definition can contain:

• Member classes
• Local classes
• Anonymous classes
• Nested top-level classes and interfaces

Member classes and local classes were explained in previous lessons. This lesson explains
anonymous classes. The next lesson will explain nested top-level classes and interfaces.

Although there are some differences, an anonymous class is very similar to a local class without a
name.

Instead of defining a local class and then instantiating it, you can often use an anonymous class to
combine these two steps.

An anonymous class is defined by a Java expression, not a statement. Therefore, an anonymous class
definition can be included within a larger overall Java expression.

Anonymous class definitions are often included as arguments to method calls, or as the right operand
to assignment operators.

An object of an anonymous class must be internally linked to an object of the enclosing class.

There is no such thing as an anonymous interface, a local interface, or a member interface.

An anonymous class can often be defined very close to its point of use. Once you become
accustomed to the somewhat cryptic syntax used with anonymous classes, this can lead to improved
code readability.
Probably the most important benefit of anonymous classes has to do with accessing the members of
enclosing classes. As with member classes and local classes, methods of an anonymous class have
direct access to all the members of the enclosing classes, including private members. Thus the use of
anonymous classes can sometimes eliminate the requirement to connect objects together via
constructor parameters.

In addition, objects of anonymous classes have access to final local variables that are declared within
the scope of the anonymous class.

An anonymous class can be particularly useful in those cases where

• There is no reason for an object of the anonymous class to exist in the absence of an object of
the enclosing class.
• There is no reason for an object of the anonymous class to exist outside a method of the
enclosing class.
• Methods of the object of the anonymous class need access to members of the object of the
enclosing class.
• Methods of the object of the anonymous class need access to final local variables and method
parameters belonging to the method in which the anonymous class is defined.
• Only one instance of the anonymous class is needed.
• There is no need for the class to have a name that is accessible elsewhere in the program.

An anonymous class cannot define a constructor. However, it can define an instance initializer. Any
arguments that you specify between the parentheses following the superclass name in an anonymous
class definition are implicitly passed to the superclass constructor.

Only one instance of an anonymous class can be created.

As with member classes and local classes, anonymous classes cannot contain static members.

As with local variables and local classes, anonymous classes cannot be declared public, protected,
private, or static.

What's Next?

The next lesson in this series will explain top-level nested classes.

Complete Program Listing

A complete listing of the program discussed in this lesson is show in Listing 10 below.
/*File InnerClasses08.java Copyright 2003 R.G.Baldwin

This program is designed to illustrate the use of local classes, and anonymous classes. It illustrates
three different implementations of
anonymous classes. It also illustrates the use of instance initializers as an alternative to constructors.

Illustrates use of local class to instantiate object to handle mouse clicked event with low-level event
handling. This class uses constructor to enable mouse events on a new extended Button class. Also
uses constructor to display the class file name.

Illustrates use of anonymous class to instantiate object to handle mouse clicked event with ow-level
event handling. This class uses an instance initializer to enable mouse events on a new extended
Button class. Also uses instance initializer to display name of class file.

Illustrates use of anonymous class, which implements MouseListener interface, to instantiate object to
handle mouse clicked event using source-listener event model. Uses instance initializer to display
name of class file.

Illustrates use of anonymous class, which extends WndowAdapter class, to instantiate object to handle
window events fired by the lose button in the upper-right corner of a Frame object, using source-
listener event model. Uses instance initializer to display name of class file.

This program produces the following class files when compiled:

GUI$1$BaldButton.class
GUI$1.class
GUI$2.class
GUI$3.class
GUI.class
InnerClasses08.class

The program produces the following output when the program is started, each button is clicked once
in succession, and then the close button in the upper-right corner of the Frame is clicked:

Local class name: GUI$1$BaldButton


Anonymous class B name: GUI$1
Anonymous class C name: GUI$2
Anonymous window listener class name: GUI$3
buttonA clicked
buttonB clicked
buttonC clicked
Close button clicked

Tested using JDK 1.4.1 under Win


************************************************/

import java.awt.*;
import java.awt.event.*;
public class InnerClasses08 {
public static void main(String[] args){
new GUI();
}//end main
}//end class InnerClasses08
//=============================================//

class GUI extends Frame{

public GUI(){//constructor
setLayout(new FlowLayout());
setSize(250,75);
setTitle("Copyright 2003 R.G.Baldwin");

//Local class w/mouse events enabled. The new


// class extends Button, and uses low-level
// event handling to handle mouse clicked
// events on the button.
class BaldButton extends Button{
BaldButton(String text){//constructor
enableEvents(AWTEvent.MOUSE_EVENT_MASK);
setLabel(text);
//Display the name of the class file
System.out.println("Local class name: " +
getClass().getName());
}//end constructor

//This is the event handling method.


public void processMouseEvent(
MouseEvent e){
if (e.getID() ==
MouseEvent.MOUSE_CLICKED){
System.out.println("buttonA clicked");
}//end if
//The following is required of overridden
// processMouseEvent method.
super.processMouseEvent(e);
}//end processMouseEvent
}//end class BaldButton

//Add button to Frame


add(new BaldButton("A"));

//This code defines an anonymous Inner Class // w/mouse events enabled. The new class
// extends Button. This class uses low-level // event handling to handle mouse clicked //
events on the button. This is an
//anonymous alternative to the local class // defined above.
add(new Button("B")
{//Begin class definition
{//Instance initializer
enableEvents(
AWTEvent.MOUSE_EVENT_MASK);
System.out.println(
"Anonymous class B name: " +
getClass().getName());
}//end instance initializer

//Override the inherited


// processMouseEvent method.
public void processMouseEvent(
MouseEvent e){
if (e.getID() ==
MouseEvent.MOUSE_CLICKED){
System.out.println(
"buttonB clicked");
}//end if
//Required of overridden
// processMouseEvent method.
super.processMouseEvent(e);
}//end processMouseEvent
}//end class definition
);//end add method call

Button buttonC = new Button("C");


//Anonymous inner class that implements
// MouseListener interface
buttonC.addMouseListener(new MouseListener()
{//begin class definition
//Instance initializer
{System.out.println(
"Anonymous class C name: " +
getClass().getName());}

public void mouseClicked(MouseEvent e){


System.out.println("buttonC clicked");
}//end mouseClicked

//All interface methods must be defined


public void mousePressed(MouseEvent e){}
public void mouseReleased(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}

}//end class definition


);//end addMouseListener call

add(buttonC);//add button to frame

//Use an anonymous class to register a window


// listener on the Frame. This class extends
// WindowAdapter
addWindowListener(new WindowAdapter()
{//begin class definition
//Instance initializer
{System.out.println(
"Anonymous window listener class " +
"name: " + getClass().getName());}

public void windowClosing(WindowEvent e){


System.out.println(
"Close button clicked");
System.exit(0);
}//end windowClosing
}//end class definition
);//end addWindowListener

setVisible(true);

}//end constructor

}//end GUI class


//=============================================//

Listing 10

Anonymous classes further notes

It is common in Java programming to find situations where you need to create a class but don't need
to bother with giving it an explicit name.

For example, to obtain the size of a panel you could statements like this

Dimension d= getSize();
int width = d.width;
int height= d.height;

where a Dimension object is returned from a method and then used to obtain the width and height
values.

But why bother to create a variable for this since it will never be used again and only take up memory
space. Instead, you could replace the code with
int width = getSize().width;
int height = getSize().height;

where the compiler keeps track of the Dimension object from which we obtain width and height.

We can in fact cascade several such calls, using the object returned in the left method to call the next
method on the right:

a = getA().methodB().aMethodC().variableX;

This anonymity eliminates from the code a lot unnecessary named objects and makes it more
readable.

With the inner classes we can take this to another level by creating and instantiating a class without
bothering to give it a name. In the code below an instance of the ActionListener class is created in the
argument of the addActionListener method:

..
public class AnOuterClass extends Applet
{
int i=0;
Button bt = new Button("OK");
public AnOuterClass()
{
bt.addActionListener
( // Method argument
new ActionListener() // no name given to this object
{
public void actionPerformed(ActionEvent e)
{
i++;
System.out.println("Pressed "+i+" times");
}
}
);
add(t);
}
}

Here in one step we created an implementation of the ActionListener interface and created an
instance of it for use by the button.

Now the compiler will create a class file name AnOuterClass$1.class where a number, in this case
"1", is used to identify the class files for anonymous inner classes.

With a frame for an application or a popup window, we can use an anonymous WindowAdapter
subclass to catch WindowClosing events and properly exit from the application:
WindowListener listener = new WindowAdapter()
{
public void windowClosing(WindowEvent e){
System.exit(0); }
};
// and add it to the frame.
tf.addWindowListener(listener);

Or the even more compact:

tf.addWindowListener
( new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
}
);

You might also like