Inner classes in java / Everything about inner classes in java

Inner Class : Meaning

As its name states, a class inside another class is called an Inner Class. Inner classes share special relationship with its containing class in that it has access to all the members of outer class(even private ones). This is because an inner class is also a member of outer class just like other fields and methods.

Inner Class : Types

An inner class can be of three types.

  1. Normal or Regular Inner class(normally referred to as just Inner class)
  2. Method Local Inner class.
  3. Anonymous Inner class.

1. Inner Class

This section will dig into all the details of an inner class. For simplicity, consider the following classes

class Outer {
   private String outerField = "Outer";
 
  class Inner {
      private String innerField = "Inner";
   }
}

Here Outer is the outer class and Inner is the inner class which is contained inside Outer.

Creating object of Inner class

An inner class is inside another class which is the outer class. Thus, an inner class cannot exist without outer class and the same applies to its object(or instance). An object of inner class cannot exist without an object of outer class. This means that for creating an instance of inner class, you need to have an instance of outer class. Thus, object of inner class can be created by the below given method.

// first, create object of outer class
Outer outerObject = new Outer();
// create object of inner class
Inner innerObject = outerObject.new Inner();

As clear from the example, to create an object of inner class, an object of outer class is necessary. There is also a short-hand method for creating inner class object.

Inner innerObject = new Outer().new Inner();

This method also requires outer class object. Just Remember….An object of inner class cannot be created without an object of its containing (or Outer class).

Creating Inner class Object Within Outer Class

Previous example assumes that you are instantiating inner class from somewhere outside the outer class. But, in most cases, an object of inner class is required inside the outer class only, since outer class makes use of inner class. So how do we create an object of inner class from inside outer class. Consider modified sample class below.

class Outer {
   private String outerField = "Outer";
 
   public void createInnerClassObject() {
      // create an object of inner class
      Inner innerObject = new Inner();
   } 
   class Inner {
      private String innerField = "Outer";
   }
}

Notice the line Inner innerObject = new Inner();. Previously it was stated that an inner class object cannot be created without an object of outer class but the above code snippet is doing it. Confused !!!! 
Above syntax is valid because it is written inside a method of outer class. When this code is executing, there is already an instance of outer class present, which is running the method.

Always Remember, In order to create(or access) an object of inner class, there should be an instance of outer class.

To summarize,

  1. When an object of inner class is created from within outer class, it can be created directly as Inner innerObject = new Inner();.
  2. When an object of inner class is created from outside of outer class, it needs to be created as Inner innerObject = new Outer().new Inner();.
When objects of outer and inner class are printed, following is the output generated:
Outer class instance : [email protected]
Inner class instance : [email protected]


Referencing Outer Class instance, fields and methods from Inner class

An inner class is also a member of its containing class like other fields and methods. Thus, it can access other fields and methods of outer class in the same way as other fields and methods access one another, directly. This holds true when accessing outer class fields and methods from inner class.
But, when referring the instance of outer class, there is a difference. In order to reference the current instance of a class, this keyword is used. In case of inner class, using this inside inner class refers to current instance of inner class and not its outer class. For referencing instance of outer class from inner class, we need to add class name to this keyword. Thus, to reference outer class instance from inner class, use Outer.this syntax. Refer to below example for understanding.

class Outer {
   private String outerField = "Outer";
 
   public void createInnerClassObject() {
      // create an object of inner class
      Inner innerObject = new Inner();
   } 
   class Inner {
      private String innerField = "Outer";
 
      public innerClassMethod() {
         // access outer class field
         System.out.println("Outer field : " + outerField);
         // access inner class instance
         System.out.println("Inner instance : " + this);
         // access outer class instance
         System.out.println("Outer instance : " + Outer.this);
      }
   }
}

Output

Outer field : Outer
Inner instance :
Outer instance :

2. Method Local Inner Class

As name suggests, a class defined inside a method is a Method Local Inner Class. Yes it is possible. You can define a class inside a method as shown below.

// outer class
class Outer {
 
   // outer class method
   public void createClass() {
      // class inside a method
      class Inner {
         // inner class method
         public void innerMethod() {
            System.out.println("Method local inner class");
         }
      } // inner class ends
   } // method ends
}

Above code has a class Outer containing a method. This method defines a class which is inside the method body, hence called method local inner class. Notice that Inner class also has its own method definition.

Instantiating a Method local inner class

Preceding code declares a method local inner class but it does not create any object of inner class. Now the question arises, how to create an object of method local inner class. Since a method local inner class is defined inside a method, it is visible only inside that method and its object can also be created only inside that method. Below code creates an object of method local inner class and calls its method.

// outer class
public class Outer {
 
   // outer class method
   public void createClass() {
      // class inside a method
      class Inner {
         // inner class method
         public void innerMethod() {
            System.out.println("Method local inner class method called");
         }
      } // inner class ends
      // create inner class object
      Inner innerObject = new Inner();
      // call inner class method
      innerObject.innerMethod();
   } // outer class method ends
 
   // Main method
   public static void main(String[] args) {
     // create object of outer class
     Outer outerObject = new Outer();
     // call outer class method
     outerObject.createClass();
   }
}

When the above code is executed, following is the output

Method local inner class method called

This shows that when outer class method is called, it creates an object of inner class and calls the inner class method.

Method Local Inner Class : Points to Remember

  1. Statement which creates an object of method local inner class should be written outside class body. Thus, the line Inner innerObject = new Inner(); should come after the local class ends.
  2. A method local inner class can be instantiated only inside the method in which it is declared. This makes sense since a method class is visible inside the method only, thus its object can be created inside that method only.
  3. A method local inner class can not access the local variables of the method in which it is declared. If it needs to access them, they should be marked final. This is applicable before java 8.
  4. You cannot access a method local variable inside a method local inner class and then re-assign it. This will be a compiler error. This is applicable from java 8 since versions prior to java 8 will not even allow you to access a method local variable inside the inner class.
  5. A method local inner class can access the fields and other methods of the class to which the method containing inner class belongs.
  6. A method local inner class can access the static fields and other static methods of the class to which the method containing inner class belongs only when the containing method is static.

3. Anonymous Inner Classes

Anonymous means whose name is not known. In context of java, an Anonymous class is one which has no name. The term Anonymous class can only be applicable to Inner classes since outer classes should have a name. An Anonymous class is an inner class because it will always be defined inside another class.

Anonymous Class : Types

In actual, an anonymous class is an implementation of an already existing class or an interface which is written somewhere else but it is defined again inside another class as required. This may sound confusing but the examples that follow will clarify the concept. Based on whether the anonymous class is an implementation of a class or an interface, it may belong to following two categories

A. Sub-class of a class
Let’s start with an example first

// Already existing class
class Website {
   public void printName() {
      System.out.println(“No website till now”);
   }
}
class SearchEngine {   // Notice the syntax
   Website w = new WebSite() {
      public void printName() {
         System.out.println(“Website is codippa.com”);
      }
   };
}

In the above example, there is a class named Website which is already created. Another class SearchEngine redefines this class, implements its method and assigns it to a reference variable which is of the same type as the actual class. It is also possible to call the newly implemented method using this reference variable.
Remember that the newly implemented Anonymous class is a sub-class of the actual class. It follows Polymorphism and its object can be passed anywhere the object of Website class is expected. Go through the below example for illustration.

class Website {
   public void printName() {
      System.out.println(“No website till now”);
   }
}
class SearchEngine {  
   // Notice the syntax
   Website w = new WebSite() {
      public void printName() {
         System.out.println(“Website is codippa.com”);
      }
    };

    // Expects an instance of Website class
    public void getWebsite(Website web) {
        // call the method of Website class
        web.printName();
    }
   
    // Main method
    public static void main(String[] args) {
        // create an object of this class
        SearchEngine obj = new SearchEngine();
        // call its method and pass instance of Website class
        obj.getWebsite(obj.w);
    }

}

Instead of pre-defining the implementation of Website class, it can be defined where required, that is while calling the getWebsite method. Thus main method can be modified as

public static void main(String[] args) {
      SearchEngine obj = new SearchEngine();
      // Notice the implementation of Website class as argument
      obj.getWebsite(new Website() {
         public void print() {
            System.out.println(“Dynamic implementation”);
         }
      });
}

The above implementation is not assigned to any reference variable, it has no name and hence the name Anonymous.

It is not necessary that both classes are in the same file or package. They can be located anywhere relative to each other.

B. Implementer of Interface

An anonymous class can also be defined as the implementer of an interface. In this case, it will define the implementation of methods declared in the interface and can be passed anywhere the object of interface is expected. Refer below example to make it clear.

interface WebInterface {
     // interface method declaration
     public void print();
}

class SearchEngine {  
   // Notice the syntax
   WebInterface w = new WebInterface() {
      // Interface method implementation
      public void printName() {
         System.out.println(“Website is codippa.com”);
      }
    };

    // Expects an instance of WebInterface interface
    public void getWebsite(WebInterface web) {
        // call the method of WebInterface
        web.printName();
    }
   
   // Main method
    public static void main(String[] args) {
        // create an object of this class
        SearchEngine obj = new SearchEngine();
        // call its method and pass instance of WebInterface
        obj.getWebsite(obj.w);
    }

}

 

As before, implementation of interface as anonymous class can be created where required as shown below.

public static void main(String[] args) {
      SearchEngine obj = new SearchEngine();
      // Notice the implementation of WebInterface as argument
      obj.getWebsite(new WebInterface() {
         public void print() {
            System.out.println(“Dynamic implementation”);
         }
      });
}

Notice the use of new keyword before the interface name. Anonymous class is the only place where it is possible.

Polymorphism in Anonymous classes

As stated earlier, Anonymous classes follow Polymorphism. Since they are subclasses, they should follow Polymorphism. This section will detail out how. Consider the below class.

class Metal {
  
    public void printThickness() {
       System.out.println(“Thick enough”);
    }
}

 

class MetalDriver {
    // Anonymous class definition
    Metal metal = new Metal() {
       public void printThickness() {
          System.out.println(“Thick enough”);
       }
       // new method
       public boolean hasLustre() {
           return false;
       }
    };

     public void printMetalDetail(Metal m) {
         // call method present in actual class definition. No problem
         m.printThickness();
        // call newly defined method in Anonymous class. Compiler Error!!!
         m.hasLustre();
     }

}

Above code defines a class Metal with a single method. This class is implemented again anonymously in another class MetalDriver where a new method is added to its definition which is not present in actual class. Now when this new method is called, the compiler complains with an error The method hasLustre() is undefined for the type Metal. This is because anonymous class is a subclass while the reference is of actual class(which is the parent). Compiler could not find the new method in parent class and flags an error.
Thus, the error establishes two facts: (i) Anonymous class is a sub-class of actual class and (ii) Anonymous class definitions follows Polymorphism.

Anonymous class : Benefit

Suppose you need to call a method that takes an argument of a type which is an interface. Now, this interface belongs to some external library and you do not have a class which implements this interface. How will you call this method. If you pass null, then there is a risk of run time exceptions. Anonymous class to the rescue. Now can create an anonymous class which implements this interface and pass it over the method providing implementation of its methods as per your needs. Example follows.

// Interface from external Library
interface External {
   public void interfaceMethod();
}

class CalledClass {

   // Method to called. Takes an argument of interface type
   public void toBeCalled(External e) {
       e.interfaceMethod();
   }
}

Above code has an interface which has a method and a class whose method you need to call from your code. Method of this class takes an argument of type interface but you do not have a class which implements this interface. If you pass null to the method argument, it will straightaway throw a java.lang.NullPointerException. Have a look at how you can call this method using Anonymous class.

class CallingClass {
   // Main method
   public static void main(String[] args) {
      CalledClass obj = new CalledClass();
      // call method using Anonymous class
      obj.toBeCalled(new External() {
           public void interfaceMethod() {
               // your code
           }
      });
  }
}

Notice the use of Anonymous interface implementation to call the method. This is the biggest benefit of Anonymous classes.

Let’s tweak in

  1. When a class containing inner class is compiled, then 2 class files are generated : one for outer class and one for inner class. Example, Outer.class and Outer$Inner.class for outer class Outer and inner class Inner respectively..
  2. Class file of inner class can not be directly executed using java command.
  3. A normal inner class can not have static data members or methods.
  4. An inner class can have a constructor.
  5. A method local class can be instantiated only inside the method in which it is defined.
  6. A method local class defined in static method can access only static members of the enclosing class.
  7. An anonymous class which implements an interface, can implement only one interface as opposed to normal classes which can implement many.
  8. An anonymous class can not extend a class and implement an interface at the same time which normal classes can.
  9. Anonymous class definitions end with }; (Notice the semi-colon).
  10. Anonymous classes which are defined as an argument while calling a method end with }); (Notice the semi-colon).
  11. You can not call a method on anonymous class reference which is not present in actual class.
  12. An inner class preceded with static is known as a nested class, not an inner class.