Architecture & DesignNested Classes and Their Use in Java

Nested Classes and Their Use in Java

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Overview

In Java, it is possible to declare a class within another class. This is called a nested class. The visibility and scope of the nested class is bounded by the class within which it is declared. Thus, if a class B is declared within class A, it means that the existence of the class B is dependent on the existence of class A. Also, its scope is bounded by the scope of the encompassed class. The enclosing class B is a member of class A. As a result, class B has full access of the private members of class A, the enclosing class, but class A does not have access to the private members of class B, the nested class.

package com.mano.examples;
public class A {
   private int privateAInt;
   protected int  protectedAInt;
   public A(){
      privateAInt = 10;
      protectedAInt = 20;
      // privateBInt = 11;     // not OK
      // protectedBInt = 22;   // not OK
   }
   class B{
      private int privateBInt;
      protected int  protectedBInt;
      public B(){
         privateAInt = privateAInt * 10;       // OK
         protectedAInt = protectedAInt * 10;   // OK
         privateBInt = 11;
         protectedBInt = 22;
      }
      public void funcB(){
         System.out.println("privateAInt = " +
            privateAInt);
         System.out.println("privateBInt = " +
            privateBInt);
         System.out.println("privateAInt = " +
            protectedAInt);
         System.out.println("privateAInt = " +
            protectedBInt);
      }
   }
   public void funcA(){
      // not OK
      System.out.println("privateAInt = " +
         privateAInt);
      // System.out.println("privateBInt = " + privateBInt);
      // not OK
      System.out.println("privateAInt = " +
         protectedAInt);
      // System.out.println("privateAInt = " + protectedBInt);
      B b = new B();
      b.funcB();
   }
}

A nested class also can be declared locally within a block.

Types of Nested Classes

A nested class can be declared as either static or non-static. When we apply the static modifier to a nested class, it is called a static nested class; otherwise, it is non-static. The property of the nested static class is that it can directly access only the static members of the enclosing class. Other members of the enclosing class are accessible only via an object of that class. Due to this restriction, only in a rare circumstances will we need a static nested class. Compare the code below with the example code given above.

package com.mano.examples;
public class A {
   private int privateAInt;
   protected int protectedAInt;
   static int staticAInt;
   public A(){
      privateAInt = 10;
      protectedAInt = 20;
      staticAInt = 30;
      // privateBInt = 11;     // not OK
      // protectedBInt = 22;   // not OK
      B.staticBInt = 33;   // OK
   }
   static class B{
      private int privateBInt;
      protected int  protectedBInt;
      static int staticBInt;
      public B(){
         // privateAInt = privateAInt * 10;        // not OK
         // protectedAInt = protectedAInt * 10;    // not OK
         staticAInt = staticAInt *10;
         A a = new A();
         // OK
         a.privateAInt = a.privateAInt * 10;
         // OKprotectedAInt = a.protectedAInt * 10;
         privateBInt = 11;
         protectedBInt = 22;
      }
      public void funcB(){
         // System.out.println("privateAInt = " + privateAInt);
         System.out.println("privateBInt = " + privateBInt);
         // System.out.println("privateAInt = " + protectedAInt);
         System.out.println("privateAInt = " + protectedBInt);
      }
   }
   public void funcA(){
      System.out.println("privateAInt = " + privateAInt);
      // not OK
      // System.out.println("privateBInt = " + privateBInt);
      System.out.println("privateAInt = " + protectedAInt);
      // not OK
      // System.out.println("privateAInt = " + protectedBInt);
      B b = new B();
      b.funcB();
   }
}

There is another type of nested class, called an inner class. The inner classes are the most frequently used non-static nested class in Java. They can access all the members of the enclosing class and work in a similar fashion as other non-static nested classes. In fact, all non-static nested classes are nothing but inner classes. They can be declared within another class or in a block or method.

package com.mano.examples;
import java.util.Random;
public class A {
   int intA = 10;
   void show(){
      for (int i = 1; i < 10; i++){
         class InnerB {
            void func(int val){
               System.out.println(intA * val);
            }
         }
         Random r = new Random();
         InnerB ib = new InnerB();
         ib.func(r.nextInt(100));
      }
   }
}

There is another type of inner class, called an anonymous class. This is an inner class that does not have a name. Nested classes are extensible and are used in association with handling events in Java. Here is an example to illustrate the idea.

package com.mano.examples;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
public class MouseEventApp extends JFrame {
   public MouseEventApp(){
      setSize(400, 350);
      setTitle("Anonymous class demo");
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      setVisible(true);
      // inner class
      addMouseListener(new MouseAdapter() {
         @Override
         public void mouseClicked(MouseEvent e) {
            repaint();
         }
      });
   }
   public void paint(Graphics g){
      Random r = new Random();
      getContentPane().setBackground
            (new Color(r.nextInt(255),
                  r.nextInt(255),
                  r.nextInt(255)));
   }
}

The constructor of the MouseEventApp calls the addMouseListener method. The arguments of this method instantiate the anonymous inner class. The code within the braces of new MouseAdapter() indicates that the anonymous class extends the MouseAdapter class. Observe that the new class thus created is not named; hence, it is anonymous. It is an inner class, so it can access all the members within the scope of the outer class. Therefore, we can access the repaint method of the outer class directly.

Why Do We Need Nested Classes?

The reason is simple. They help in creating more efficient code by helping us to do the following:

  • Group related classes in to a single logical unit
  • Leverage encapsulation
  • Leverage readability and maintainability of the code

Sometimes, we need classes that assist and can be used by other classes. This particularly can be seen with the event listener classes of Java in association with its GUI components. For example, when a user clicks a button or moves the mouse pointer, this action generates an event. The application that handles the event executes a piece of code meant for that application only. This piece of code can be written in a separate class, but it does not make much sense to create one because this particular piece of code is supposed to be used only by a specific another class. Therefore, the inner class or the anonymous class is declared exactly where it is needed; in another part of the code, it may not have a value.

Sometimes, we require a code that adheres to the quality of a class coupled well to the necessity of another class. We also do not want that the private member of the outer class to be exposed in any way, leveraging the existing encapsulation norms of the enclosing class. In such a situation, we can create an inner class within the definition of the outer class. The enclosed class would then have full access to the private members of the outer class, keeping itself protected within the boundary. The inner class may be declared private to enforce strict encapsulation and hide itself.

The code becomes more maintainable and readable with the use of the inner class. A lot of unnecessary code easily can be avoided. The classes that supposedly demand one-to-one dependency can have them without any fuss or cryptic code. Suppose some event listener or filtering class definition can be created as a top-level class and that could be anywhere in the project among hundreds of Java files. Finding them can be hectic affair for the programmer. Instead, if we can implement the same idea using inner classes or anonymous classes, the code definitely becomes more readable and maintainable.

Conclusion

A class embedded within another class is called a nested class. It may be static or non-static. Static inner classes have little use. Non-static classes without a name are called anonymous classes. Java extensible uses anonymous classes in its API library. Understand that there is a good reason to design a class as a top-level class as well as some as inner classes. This is the real key to deciding the utility of inner classes in Java.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories