JavaEnterprise JavaSome Insight Into Inner Classes in Java, Part 1

Some Insight Into Inner Classes in Java, Part 1

Inner classes are essentially classes defined inside other classes and act like members of the enclosing class. There are two varieties of inner classes, static inner classes and non-static ones. The difference is suggested in the name itself, the static inner classes are associated with the enclosing class (as any other static member) while inner classes are associated with the “object” of the enclosing class. We shall explore the difference further later. Inner classes are a phenomenon of the compiler. It converts the inner classes as plain classfiles with some strange class names, the virtual machine does not distinguish between regular class’s and inner class’s class files.

For a better understanding of the concepts in this article and syntax of inner classes please read the article “SJCP Exam Preparation: Top-level and Inner Classes” here in Gamelan.

The Third Route

When you are designing a class hierarchy, you try to figure out the relationship between the classes that you decide upon. These relationships more often than not can be classified as “is a” relationship and “has a” relationship. The “is a” relationship leads to the inheritance hierarchies, as the clause suggests, the derived class “is a” kind of super class. The common Employee/Manager example has become a classic in defining this relationship.

class Employee {
  private String name;
  private Date dateHire;
  .....
  .....
  public float getSalary() {
  }
  ...
}

Now the Manager class

Class Manager extends Employee {
  private Employee[ ] subOrdinates;
  ....
  public Employee[ ] getSubOrdinates() {
    return subOrdinates;
  }
}  

The Manager class here derives from the Employee class and there has “is a” relationship with the Employee class. The object of type Manager “is” also a type of Employee.

The other relationship in object-oriented design is the “has a” relationship. This containership design is perhaps a more-used design strategy than the inheritance one. For example, the object of class Company may contain among other objects the objects of class Employee and objects of class Manager.

class Company {
  private Employee[ ]  allEmployees;
  private  Manager[ ] allManagers;
  ....
  public Manager[ ] getAllManagers() {
     return allManagers();
  }
  public void printOrganizationTree() {
  }
}

Here, the objects of class Employee and Manager are contained in object of class Company and contribute to provide a rich set of operations as would be expected on an object like Company.

There is, however, a third, less obvious, still fairly used relationship between classes, I call it the “facet” relationship. Let me explain this relationship by way of an example. An automobile object can be designed with a number of constituent objects, like the engine, the transmission, the gear train, the exhaust, and so on. There is another component in the automobile, the air conditioner which though a part of the automobile warrants an independent class of its own.

The auto AC may derive from a general class of AirConditioner, and it is adapted to fit in the automobile, yet it cannot exist on its own. The automobile must handle the interactions to the auto AC. Look carefully, it is not the case of the Automobile class implementing an interface AutoAC. For the automobile is not an AC, and neither is it supposed to manifest the properties of an AC (implement interface). The properties of the auto AC specific to the automobile, like the belt attachment, should be left to the Automobile class only; however, other objects might be interested in dealing with the public properties of the general AirConditioner class from which the AutoAirConditioner class may be derived. Inner classes very neatly solve this problem, as in the following example.

/** The general AirConditioner class */
class AirConditioner {
  ....
  public float getTemperatureMin() {
  }
  public float getTemperatureMax() {
  }
}

/** The Automobile class which has an inner class which is an AC */
class Automobile {
  private Engine engine;
  private GearBox gearBox;
  private AutoAirConditioner ;
  .....
  private class AutoAirConditioner  extends AirConditioner {
  ...
    public float getBeltPerimeter () {
      float adjusted Volume = engine.getVolume() * 1.1;
      ......
    }
  } 

  public AirConditioner getAirConditioner () {
  }
}

The object of class AutoAirConditioner is contained in the object of class Automobile much like a containership hierarchy with one difference, that the behavior of the object AutoAirConditioner as available to the other classes is limited to the interface as defined in the class AirConditioner, and the extension to this class is available only within the class Automobile.

Moreover, every member of the class Automobile is accessible in the inner class AutoAirConditioner. So, there need not be any special access methods defined in the class Automobile. The idea is that we have provided a behavior like an AirConditioner within class Automobile without extending the class and without exposing the class Automobile through any public method for this purpose. As we know that every member of the enclosing class (Automobile), even the private ones, are accessible to the inner class (AutoAirConditioner). This helps us keep the interface uncluttered and the hierarchy simple.

Another example would drive the point home very clearly. Suppose there is a requirement (by an automobile design program) to have access to all the different types of bolts used in the automobile. Now, there could be various types of bolts used, with different dimensions, size, number of threads, etc., and we need to iterate over them to either find ones that suit our requirement, of say size, or perform some calculation of, say, finding the median weight of all the bolts.

What we want is an “iterator” over the bolts. Inner classes are most suited for this kind of requirement. We define an Iterator class inside the class Automobile and return a reference to it through a public method bolIterator(). Better still, we may make the inner class anonymous, the idea is that the “name” of this inner class is going to be used only once (when its object is created in the iterator() method of the enclosing class), so we might do away with the name.

import java.util.Iterator;
class Automobile {
 Bolt[ ] boltArray;
  ......
  ......

  public Iterator boltIterator() {
    return new Iterator () {
      int count;
      public boolean hasNext() {
        return (count  < boltArray.length) ;
      }
      public Object next() {
        return boltArray[ count ++ ] ;
      }
    } ;
  } // method iterator

} 

Here, the methods next() and hasNext() of the interface Iterator may access the private members of the class Automobile. Note here that the class Automobile has nothing to do with this behavior of Iterator. All it does is provide a method that hands over an Object of type Iterator through which the rest of the world can iterate over the bolts in Automobile. The Iterator here is not a behavior of the class Automobile but a "facet" of it.

This is a big leap forward, I believe. Object-orientation provided a concept of state and behavior to the Objects. Inner classes provide state and behavior to the "members", allowing multifaceted objects.

Access Control Point

Inner classes are able to access the private members of the enclosing class due to a trick with the compiler. Inner class's classfile is a regular classfile with a strange name, e.g., Automobile$AutoAirConditioner.class. In the classfile, there is a private final reference called this$0 to the outer class. (Of course you cannot refer to it in your code, as it is synthesized by the compiler). So, through this reference, the inner class members can access the outer class. But this is not sufficient, as what we have in the outer class is a number of access methods also synthesized by the compiler.

For example, the inner class AutoAirConditioner directly accesses the private variable engine in the class Automobile, so the classfile of Automobile may contain a method,static Engine access$0(Automobile), which may return the requisite Engine object to the inner class. Of course, all this happens under the covers.

So far, we have seen how we make use of this access by providing another "facet" of behavior to the classes. We may use the capacity of inner classes as regular classes to maintain a state, to provide a means to regulate this access.

In Part 2, we will illustrate this with an example, as well as look at anonymous and static inner classes further.

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