Baldwin explains nested top-level classes, and illustrates a very useful polymorphic structure where nested classes extend the enclosing class and override methods declared in the enclosing class.
Published: May 25, 2004
By Richard G. Baldwin
Java Programming Notes # 1642
This series of lessons is designed to teach you about the essence of Object-Oriented Programming (OOP) using Java.
The first lesson in this overall series on OOP was entitled
The Essence of OOP Using Java, Objects, and Encapsulation.
Inner classes
This lesson is the last lesson in a six-lesson miniseries designed to
teach you about inner classes. The topics covered by the lessons in
this miniseries are:
The first lesson in the six-lesson miniseries on inner classes was entitled
The Essence
of OOP using Java, Static Initializer Blocks. The previous lesson
was entitled
The Essence of OOP using Java, Anonymous Classes.
Another browser window
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.
Further reading
For further reading, see my extensive collection of online Java tutorials at Gamelan.com. A consolidated index is available at www.DickBaldwin.com.
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:
Can also contain other class definitions
You have also learned that a class definition can contain the following
four kinds of inner classes:
Previous lessons explained member classes, local classes, and anonymous
classes. This lesson will explain nested top-level classes and interfaces.
(Note that it is questionable whether a nested top-level class should be referred to as an inner class. Unlike an object of a member class, local class, or anonymous class, 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 a nested top-level class or interface?
I'm going to begin my discussion with a quotation from one of my favorite
authors, David Flanagan, author of Java in a Nutshell.
"A nested top-level class or interface is defined as a static member of an enclosing top-level class or interface. The definition of a nested top-level class uses the static modifier ... Nested interfaces are implicitly static ... and so are always top-level. A nested top-level class or interface behaves just like a 'normal' class or interface ... The difference is that the name of a nested top-level class or interface includes the name of the class in which it is defined."
Why use nested top-level classes or interfaces?
Again, according to Flanagan,
"Nested top-level classes and interfaces are typically used as a convenient way to group related classes."
Can be particularly useful when ...
A particularly useful implementation of top-level classes occurs when
the nested classes extend the enclosing class and override methods that are
declared or defined in the enclosing class. This makes it very convenient
to construct a hierarchical API, which exhibits very useful polymorphic behavior,
and which cannot easily be expanded.
(Without getting into the technical details, I will cite the Java2D API as an example, which makes heavy use of nested top-level classes for this purpose. See, for example, the classes named Point2D, Poind2D.Double, and Point2D.Float. According to Sun, the Point2D class is "the abstract superclass for all objects that store a 2D coordinate. The actual storage representation of the coordinates is left to the subclass." With these classes, when you perform an operation on one of the subclass objects, whose reference has been stored as the superclass type, runtime polymorphism kicks in and the appropriate method is invoked for the actual type of object on which the method is invoked.)
Purpose of this lesson
This lesson explains top-level nested classes from a practical viewpoint, and discusses a sample program that creates and exercises a simple class hierarchy as described above.
Miscellaneous comments
The following are a few of the characteristics of nested top-level classes,
which are not necessarily illustrated by the sample program that follows
later.
A nested top-level class must be declared static within another top-level
class. Methods in a nested top-level class have access to the static
members of its containing class.
Nested top-level classes can only be nested within other top-level classes.
They cannot be defined inside member classes, local classes, or anonymous
classes. However, nested top-level classes can be nested to any depth.
Typically nested top-level classes are referred to by their fully-qualified
name, such as Poind2D.Double, where Point2D is the
name of the enclosing class and Double is the name of the nested
class. According to Flanagan, in the same sense that it is possible
to use an import directive beginning with a package name to eliminate the
requirement to include the package name in a reference to a class, it is
also possible to use an import directive beginning with an enclosing class
name to eliminate the requirement to include the enclosing class name in
a reference to a nested class. However, I have never been able to
make this work. Perhaps I don't fully understand the required syntax
for the import directive.
Smoke and mirrors
In an earlier lesson, I explained that every class definition in a Java
program, including nested top-level classes, member classes, local classes,
and anonymous classes, produces a class file when the program is compiled.
According to Flanagan,
"The Java Virtual Machine knows nothing about nested top-level classes and interfaces or the various types of inner classes. Therefore, the Java compiler must convert these new types into standard non-nested class files that the Java interpreter can understand. This is done through source code transformations that insert $ characters into nested class names. These source code transformations may also insert hidden fields, methods, and constructor arguments into the affected classes."
Example class file names
For example, compilation of the sample program discussed later in this
lesson produces the following class files:
The first file in the above list is the driver program that is used to
exercise the three class files that follow the first one in the list.
The second file named Shape.class represents the enclosing class named
Shape. The remaining two files represent the two static classes
named Circle and Rectangle, which are nested within the class
named Shape. (Note how the file name is constructed from
the name of the enclosing class and the nested class.)
Enough talk, let's see some code
The paragraphs that follow will explain a program named InnerClasses09, which is designed specifically to illustrate nested top-level classes. I will discuss the program in fragments. A complete listing of the program is provided in Listing 7 near the end of the lesson.
Rectangle area = 6 Figure 1 |
The beginning of the definition for the class named Shape is shown
in Listing 1. (Once again, see Listing 7 for a listing of the
complete program.) This class contains two nested static classes
named Rectangle and Circle.
(Normally a class like this would be declared public. However, declaring a class public requires the source code for the class to be in a separate file. In order to keep all the code in this program in a single source code file, I caused this class to be package-private instead of public.)
abstract class Shape{ |
public static class Rectangle extends Shape{ |
public void area(){//override the area method |
public static class Circle extends Shape{ |
(The overridden area method in each of the two enclosed classes uses a formula for calculation of the area that is appropriate for an object of that type. That is the beauty of runtime polymorphism. When the reference to an object of either class is saved as type Shape, and the area method is invoked on that reference, the version of the area method executed is appropriate for the actual type of object on which the method is invoked. However, the using programmer doesn't have to worry about the actual type of the object.)Listing 4 also signals the end of the Shape class, which encloses the definitions of the Rectangle and Circle classes.
public class InnerClasses09{ |
(Note that this is similar to accessing a static variable of the Math class as Math.PI.)Invoke the area method on the object
Rectangle area = 6 Figure 2 |
aShape = new Shape.Circle(3); |
Circle area = 28.274333882308138 Figure 3 |
At this point, you may find it useful to compile and run the program
shown in Listing 7 near the end of the lesson.
A nested top-level class must be declared static within another top-level
class. Methods in a nested top-level class have access to the static
members of the containing class.
/*InnerClasses09.java |
Copyright 2003, Richard G. Baldwin. Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.
Richard Baldwin is a college professor (at Austin Community College in Austin, Texas) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.
Richard has participated in numerous consulting projects, and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas. He is the author of Baldwin's Programming Tutorials, which has gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.
Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.
-end-