JavaEnterprise JavaSome Insight Into Inner Classes in Java, Part 2

Some Insight Into Inner Classes in Java, Part 2

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

Review Part 1

In the first half of this article, we began examining the benefits of inner classes, such as adding a “facet” to the behavior of an enclosing class to enrich its interactions. Then we touched upon their ability to act as access control points, where the inner class can be used to provide controlled access to some resource or to define isolated callbacks. Here, we’ll follow up on this point and move on to discuss callbacks “on the fly” and static inner classes.

With regard to using inner classes as regular classes to maintain a state for the purpose of controlling access, consider the following example.

Suppose we have a DatabaseService that maintains a pool of database connections. This service class has an execute(String query) method which takes out a connection from the pool of connections, executes a query and puts back the connection in pool and returns the result. This works well with a normal requirement, now suppose a power hungry application requires a handle to the connection object itself. However, we do not want this application to misuse our precious Connection object and we want only “n” operations allowed on that Connection object as requested by the power hungry application.

We may define our DatabaseService class as follows.

class DatabaseService {
  private Connection[ ] pool;
  .....
  public ResultSet execute (String sqlstmt) {
   ..........
  }
  private  Connection getFreeConnectionFromPool() {
   ......
  }
  private void checkinFreeConnection (Connection conn) {
   .......
  }
  
  public ControlledConnection getControlledConnection (  ) {
    return new ControlledConnectionImpl();
  }
  
  .....
  // inner class to encapsulate one Connection object and keep it under control
   class ControlledConnectionImpl implements ControlledConnection {
    private Connection myConnection;
    private int operationCount;
    private ControlledConnection() {
      //access private method of class DatabaseService
      myConnection = getFreeConnectionFromPool();
    }
    public Object operateOnConnection (String operation,  Object[ ] args) {
      operationCount ++
      if (operation.equals("createStatement")){
      }
      else if (operation.equals("prepareStatement")) {
      }
      else if (operation.equals("commit")) {
      }
      ......
    }
  }
}

This is just skeletal code but it brings out the concept clearly. The inner class ControlledConnectionImpl implements an interface called ControlledConnection. This interface has one method that the power hungry application has an access to, operateOnConnection(). If you look closely the constructor of ControlledConnectionImpl class is private, so only instances of DatabaseService only can create this object. So the external application can get this object by calling the method getControlledConnection().

Remember that the method getFreeeConnectionFromPool() in the DatabaseService class is private thus out of bounds for the external application. Now there are two ways that this inner class can control the access. One by implementing the interface of the resource that it want to control and providing only selective controlled API to the external application, or as above, provide an API like operateOnConnection() and allow only some operation with any access check as necessary. For example you may decide to allow only three operations per controlled connection so you can introduce a member variable, operationCount, and increment it whenever the operateOnConnection() method is called.

Callbacks on the Fly

Anonymous inner classes are the inner classes that are defined inside methods of the enclosing class, these do not have a name because these are not to be used anywhere other than that method call.

Suppose you have a GUI application designed with the menu items worked out and the widgets and their roles defined. Then you want to have a Button to be placed at the bottom, which would close this frame and open a new window. This is an operation which is not to be performed by any other UI component but this solitary button, your main JFrame class has already implemented the interface ActionListener as it contains the code for some other buttons on the man UI, you do not want to clutter the code there by adding some “if” statements and you would not like to write a separate class to handle this interaction. The best way probably is to make use of an anonymous inner class to be this new button’s ActionListener.

.......
JButton  nextButton = new JButton("Next");
nextButton.addActionListener (new ActionListener() {
                                public void actionPerformed(ActionEvent ae) {
				  frame.dispose();
				  frame = new NextFrame();
			                  frame.setVisible(true);
                                }
                              }
                             );

This looks like somewhat cryptic code but it is very convenient and keeps the code form becoming scattered. Here, we have created the nextButton and added the action listener to it. The argument to the addActionListener() method should be the instance of a class that implements ActionListener interface. Our anonymous inner class implements the interface ActionListener.

Static Inner Classes

Inner classes can also have a modifier “static”, as you would expect the implicit reference to the enclosing class’s object is missing here. (As is missing from static methods) and the instance of static inner class can exist without the instance of the enclosing class. Only static members of the enclosing class are accessible to the members of static inner class (As are available to the static methods). What is so special about static inner classes when they do not have the reference to the enclosing class? In fact, static inner classes are just like top-level classes. Some see them as extensions to packaging. However, you should not use the static inner classes as just instrument to use the namespace of the outer class. There should be a strong association between the static inner class and the enclosing class.

The enclosing class takes the role of the primary class and the static inner class takes the supporting cast, as much as the inner class has no meaning without the enclosing class. The Java swing API is rife with the use of static inner classes. Take the example of the new SpringLayout class added in v 1.4. If you have ever used a GUI builder tool you would have seen that tool uses the absolute positioning of the GUI widgets in the container (using setBounds() or setLocation()) rather than using a Layout Manager. The new SpringLayout class is meant to be used for a requirement like this. For more details on SpringLayout see How to Use SpringLayout in the Java Tutorial.

The SpringLayout class has a static inner class SpringLayout.Constraints defined. As the name suggests the Constraints class defines some constraints applicable to the container and also to the widgets in the container. There is a method in the SpringLayout class, getConstraints(Component c) , which returns the SpringLayout.Constraints object associated with the Component. We can create our own Constraints object and set the constraints by calling add(Component, Object) method on Container. As you see that the Constraints class though syntactically looks very much like a top-level class but the usage of it is limited as a supporting class to the enclosing class.

Conclusion

We have seen how inner classes can simplify some design by enriching the classes in which they are defined. We have seen how they might add a “facet” to the behavior of enclosing class thus enriching its interactions with other classes.

We have also explored the role of inner classes as access control points where the inner classes can be used to provide controlled access to some resources by using the state of the inner classes, again without affecting the behavior of the enclosing class in any way. We have seen the use of anonymous inner classes as places to define isolated callbacks.

Finally, we saw the use of static inner classes as helper classes in defining the role of the main class. Inner classes play a significant role in object-oriented design, careful use of inner classes help in cleaner and uncluttered class hierarchies and provide strength to the main classes by supplementing them.

About the Author

Nasir Khan is a Sun Certified Java programmer, with a B.E. in electrical engineering and a masters degree in systems. His areas of interest include Java applications, EJB, RMI, CORBA, JDBC and JFC. He is presently working with BayPackets Inc. in high-technology areas of telecom software.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories