The OuterClass defines two inner classes: StaticNestedClass and InnerClass. The StaticNestedClass is declared with the static modifier, whereas the InnerClass is nonstatic.. The static and nonstatic inner classes have different significance and are therefore categorized separately. Two additional types of inner classes are local and anonymous.
Why Use Nested Classes?
There are several compelling reasons for using nested classes:
- They allow logical groupings of related classes.
- They provide increased encapsulation.
- They lead to more readable and maintainable code.
Sometimes a class may be useful to only one other class. A typical example of this is the event listener classes defined in Java for its GUI components. For instance, let’s say we use a command button in several applications. When the user clicks the button, the application executes a certain piece of code specific to that application. We may now declare a class that defines a method to process the click action initiated by the user. As such, a class may not have any significance outside the declaring class and therefore may be declared “inner.”
As another example, suppose that we are required to filter out all the odd numbers in a randomly generated array of integers. This filtering may be done on several random arrays. In such a situation, we would create a class that defines filtering methods. Such a class would have not much value outside the class that creates random arrays—meaning that it is not really reusable outside the random array-generation class. This filtering class would be an ideal candidate for creating an inner class. (We create this filtering class in the next section.)
The second useful benefit of creating nested classes is that it allows increased encapsulation. Consider that the MindStickModem class from pervious posts(interface sections) is required to create an object for processing the internal read buffer. If we create a class outside the definition of MindStickModem, we would need to provide the getter/setter methods on the read buffer attribute of the MindStickModem class, making it accessible to the other code in the application. We may not want to do this—that is, to expose the private read buffer to the outside code. Therefore, we could create an inner class within the definition of the MindStickModem class. This class would have access to all the private members of the MindStickModem class, thus keeping them protected from exposure to the outside world. This inner class may also be declared private to hide it from the outside world. As we can see, this increases encapsulation—the data and the methods that operate on them are kept together.
Lastly, the use of inner classes makes the code more readable and maintainable. Just imagine if the event listener and the filtering classes we just discussed were declared as outside classes. In this case, the definitions of these classes could be made anywhere in the project, and the project itself may consist of hundreds of Java files. Thus, we could easily get lost in searching for class definitions in a large project. Creating and keeping these classes embedded in a top-level class where they are used makes the code more readable and maintainable.