Static Nested Classes
Compiling a class with a nested class creates two separate class files.
Why Place One Class Inside Another
Most Java classes you have written so far probably sit at the top level of a file, each one standing on its own. Java also allows a class to be declared inside the body of another class. When that happens, the inner class is called a nested class. This article focuses on one particular kind of nested class: the static nested class, which carries the static modifier in its declaration.
The usual reason for placing one class inside another is organization. A helper type that only makes sense in the context of a larger type can be kept right next to that larger type, so the code describing one concept lives together. Placement also changes how the inner class is named, referred to, and used, and those changes are the main subject of this article.
What do you think happens?
You write one class and place another class inside its body, then compile the single source file. How many class files do you expect to find in the build output?
Reveal answer
Two class files: one for the outer class and one for the nested class.
The nested class sits physically inside the outer class's source, so it is tempting to assume its compiled form is tucked inside the outer class's output. It is not. The compiler produces a separate class file for the nested class. Nothing in the code asks for two files; the compiler handles this automatically.
What the Compiler Writes to Disk
Follow one source definition through the compiler. The source file defines an outer class called WireFrameModel, and inside its body it declares a static nested class called Line. You give the compiler one source definition. The compiler produces two class files, and the outer class's own file is one of them. The other is the file for the nested class.
The nested class's file is named WireFrameModel$Line.class. The name combines three pieces: the outer class name, a dollar sign, and the nested class name. That combined name ties the file back to the class that contains it. When you inspect a build folder later, look for the $-separated name to find a nested class.
A single source definition that contains a nested class produces two separate class files. The nested class is stored in its own file, not inside the outer class's file. Expect one class file per class when you inspect compiled output.
Declaring a Static Nested Class
A static nested class is a class declared inside another class with the static modifier, and it is part of the static structure of its containing class. The class that contains it is called the outer class or the containing class.
The declaration of a static nested class looks almost identical to the declaration of any other class. Two things are added. The class is written inside the body of another class, and the keyword static appears as part of its declaration. Nothing else about how the class is written needs to change.
The source's running example is a WireFrameModel. A wireframe model is a set of lines in three-dimensional space, the kind of model used to represent three-dimensional objects in graphics programs. The WireFrameModel class holds other members and also contains a static nested class named Line. That Line class represents one line, stored as two endpoints: one with coordinates x1, y1, z1 and the other with coordinates x2, y2, z2. Here the outer class is WireFrameModel and the nested class is Line.
Dune- Bookshelf is the outer (containing) class
- static class Book is the static nested class, declared inside Bookshelf's body
- Inside Bookshelf, the short name Book is enough to create an object
Inside its containing class, the static nested class is used to create objects in the usual way. The code in Bookshelf's main method writes new Book(...) with the short name, because the code sits inside the class that contains Book. The output of this program is Dune, and the trace is simply the object being created and its title printed.
Full Names and the Dollar Sign
A name for a static nested class is built from two pieces joined by a period. The first piece is the name of the class in which the nested class is declared. The second piece is the name of the nested class itself. The result is called the full name, and it is the name a program must use whenever it refers to the nested class from outside its containing class. For the source example, the full name is WireFrameModel.Line.
The full name WireFrameModel.Line uses a period, but the class file is named WireFrameModel$Line.class and uses a dollar sign. Both forms refer to the same nested class. The period form is what your source code writes when it refers to the class from outside. The dollar form is the name that appears on disk in the build output. Keep the two apart: you write the period form in code, and you look for the dollar form in the folder.
Using the Nested Class Inside and Outside
Emma- Library is a different class, so it sits outside Bookshelf
- Bookshelf.Book is the full name, containing class then period then nested class
- The commented line uses the short name Book, which this class cannot see
Tracing a reference from outside the containing class
Library's main method needs a Book object. Which name must it use, and what does that name point to?
- 1Locate the containing class
Book is declared inside Bookshelf, so Bookshelf is the outer class.
- 2Check where the reference sits
The reference is written in Library, which is outside Bookshelf. Inside Bookshelf the short name works, but here it does not.
- 3Build the full name
Join the outer class name, a period, and the nested class name, giving Bookshelf.Book.
- 4Create the object
new
Bookshelf.Book("Emma")creates a Book, and its title field holds Emma, which prints as Emma.
Outside the containing class, the nested class must be referred to as Bookshelf.Book. The short name Book works only inside Bookshelf.
What do you think happens?
In the Library class, the line Book c = new Book("Emma"); is uncommented. Does the program compile?
Reveal answer
No, it does not compile. The line that uses the short name Book breaks the program.
The source states that outside its containing class, the nested class must be referred to by its full name, containing class name, period, nested class name. Writing only Book from Library is a naming mistake. The compiler reports the error on that line, so the fix is to change it to Bookshelf.Book.
Mistakes That Break Nested Class References
Common mistake Using only the nested class name from outside the containing class
What it looks likeIn Library, writing Book c = new Book("Emma"); when Book is declared inside Bookshelf.
Why it failsOutside its containing class, the nested class must be referred to by its full name. The short name is only enough inside the containing class.
Do this insteadWrite Bookshelf.Book c = new Bookshelf.Book("Emma");Common mistake Looking for the nested class inside the outer class's file
What it looks likeOpening WireFrameModel.class expecting to find Line's compiled code there.
Why it failsThe nested class is stored in its own file, not inside the outer class's file.
Do this insteadLook for WireFrameModel$Line.class in the build output.
Common mistake Writing the dollar form in source code
What it looks likeWriting WireFrameModel$Line in a Java statement instead of WireFrameModel.Line.
Why it failsThe dollar form is the name of the class file on disk. Source code uses the period form, the full name.
Do this insteadUse WireFrameModel.Line in source, and expect WireFrameModel$Line.class in the build folder.
Common mistake Assuming one source definition with a nested class yields a single class file
The Static Structure of the Containing Class
The phrase part of the static structure matters. The source makes an analogy with static member variables. A static variable belongs to its class rather than to any single object created from that class. In the same way, a static nested class belongs to the containing class itself. Each object of the outer class does not carry its own copy of the nested class. The nested class is attached to the class as a whole.
The diagram shows the relationship in words. The nested class Line is a static member of the outer class WireFrameModel, so it is reached through the outer class name. Its full name is WireFrameModel.Line. This is why a program outside the containing class has to write the outer class name in front of it.
Checking Your Understanding
A source file defines a class Garage that contains a static nested class named Wheel. Before compiling, predict the name of the nested class's class file. Then write the full name you would use to create a Wheel from a class called Showroom, which sits outside Garage.
Hints
- The class file name combines the outer class name, a dollar sign, and the nested class name.
- Outside the containing class, the full name joins the outer class name, a period, and the nested class name.
A class Showroom uses the line Wheel w = new Wheel(); and it does not compile. Explain in one sentence why, and state which name the line must use.
Hints
- Ask whether Showroom is inside Garage's body.
- Compare the short name with the full name from the previous question.
Key Takeaways
- Compiling one source definition that contains a nested class produces two separate class files: one for the outer class and one for the nested class.
- The nested class file is named by combining the outer and nested class names with a dollar sign, such as
WireFrameModel$Line.class. - A static nested class is declared inside another class with the static modifier, and it belongs to the containing class as part of its static structure, much as a static variable belongs to its class.
- Inside the containing class, the nested class can be used with its short name. Outside it, the full name is required: the outer class name, a period, and the nested class name, as in
WireFrameModel.Line. - When a reference to a nested class fails to compile, check whether the line uses only the short nested name from outside the containing class.