Mar 18, 2016

Inner Class in Java

In Java, a class can have member classes, just like member variables and methods. Inner classes are classes defined inside another class.

Types of Inner Class

There are following types of inner classes, depending on how and where they are defined:
  • Inner classes: A class created within another class but outside any method.
  • Method-local inner classes: A class created within method of the enclosing class.
  • Anonymous inner classes:A class having no name and used for implementing interface or extending class.
  • Static nested classes: A static class created within class.

Use of Inner Class

  • Logically group classes where you need some behavior that should belong in a separate, specialized class, but at the same time needs it to be intimately tied to the class you're designing.
  • Increase the use of encapsulation.
  • Create more readable and maintainable code.

Regular Inner Class

We use the term regular to represent inner classes that are not
  • Static 
  • Method-local 
  • Anonymous 
You define an inner class within the curly braces of the outer class:

class OuterClass {

 class InnerClass {
 }
}

Accessing Inner Classes

Inner classes can only be accessed through a live instance of the outer class.


class OuterClass {

 private int x = 10;

 // inner class
 class InnerClass {

  public void seeOuter() {
   System.out.println("Outer x is " + x);
  }
 } // close inner class
}

Since the inner class is also a member of the outer class, so it can access the private members of the outer class.

Instantiating an Inner Class

To create an instance of an inner class, you must have an instance of the outer class to tie to the inner class.

From Within the Outer Class

class OuterClass {

 private int x = 10;

 public void makeInner() {
  InnerClass in = new InnerClass(); // make an inner instance
  in.seeOuter();
 }

 class InnerClass {

  public void seeOuter() {
   System.out.println("Outer x is " + x);
  }
 }
}

From Outside the Outer Class

public static void main(String[] args) {
 OuterClass mo = new OuterClass(); // gotta get an instance!
 OuterClass.InnerClass inner = mo.new InnerClass();
 inner.seeOuter();
}

Referencing the Inner or Outer Instance from Within the Inner Class

There are certain rules for inner class to refer itself or the outer class instance:
  • To reference the inner class instance itself from within the inner class code, use "this" keyword.
  • To reference the outer class instance from within the inner class code, use OuterClassName.this (example, OuterClass.this).

Member Modifiers Applied to Inner Classes

A regular inner class is a member of the outer class just as instance variables and methods are, so the following modifiers can be applied to an inner class:
  • final
  • abstract
  • public
  • private
  • protected
  • static—but static turns it into a static nested class, not an inner class
  • strictfp

Method Local Inner Class

 A method-local inner class is the one defined within a method of the enclosing class.

To use the inner class, an instance of inner class must be created within the method where the inner class is defined.
Remember, instance of the method-local inner class must be created below the inner class definition otherwise the compiler will complain. See below example.

class OuterClass2 {

 private String x = "Outer2";

 void doStuff() {
  class InnerClass2 {

   public void seeOuter() {
    System.out.println("Outer x is " + x);
   } // close inner class method
  } // close inner class definition

  InnerClass2 innerObj = new InnerClass2(); // This line must come after the class
  innerObj.seeOuter();
 } // close outer class method doStuff()
} // close outer class

Perhaps, the most important thing here is that the inner class object cannot use the local variables of the method the inner class is in.
Why not? Think about it.
As we know the local variables of the method live on the stack and exist only for the lifetime of the method in which it is declared. So, lifetime of the variable ends as the method ends. But the inner class object created within it might still be alive on the heap if in case a reference to it was passed into some other code and then stored in an instance variable. Because the local variables aren't guaranteed to be alive as long as the method-local inner class object is, the inner class object can't use them. Unless the local variables are marked final!

Member Modifiers Applied to Method Local Inner Classes

Following modifiers can be applied to a method-local inner class (obviously never at the same time):
  • final
  • abstract

Anonymous Inner Class

An anonymous inner class that has no name. See below example, 

class Dog {

 public void eat() {
  System.out.println("In class dog");
 }
}

class Animal {

 Dog obj = new Dog() { // curly brace present instead of semicolon

  public void eat() {
   System.out.println("In anonymous class dog");
  }
 }; // end
}

And here's the big thing to get:
In the line 
Dog obj = new Dog() {  

The Dog reference variable refers not to an instance of Dog, but to an instance of an anonymous (unnamed) subclass of Dog.
 You can read it as declaring a reference variable, obj, of type Dog. Then declare a new class that has no name but that is a subclass of Dog. And the curly brace is the start of the class definition. The method "eat()" after the curly brace is the overriding the method of super class Dog.

Main thing to pay attention is the end of the anonymous subclass. It has a semicolon after the curly brace as if whole class is declared as a single statement.


Suppose, Dog is an interface instead of a class.


interface Dog {

 public void eat();
}

class Animal {

 Dog obj = new Dog() { // curly brace present instead of semicolon

  public void eat() {
   System.out.println("In anonymous dog implementer");
  }
 }; // end
}

Carefully see the line,
Dog obj = new Dog() {  

It's not instantiating a Dog object—it's creating an instance of a new anonymous implementer of Dog.

 So, the type must be either a subclass of the named type or an implementer of the named interface, not both. In other words, it cannot both extend a class and implement an interface, nor can it implement more than one interface. 
An argument-defined inner class is declared, defined, and automatically instantiated as part of a method invocation.


interface A {

 public void methodA();
}

class B {

 public void methodB(A objA) {
  // some stuff here
 }
}

class C {

 public void methodC() {
  B objB = new B();
  objB.methodB(new A() { // curly brace present instead of semicolon

   public void methodA() {
    // some stuff here
   }
  }); // end
 }
}

Static Nested Inner Class

Static nested classes are inner classes marked with the static modifier. 
Note that the class itself isn't really "static"; there's no such thing as a static class. The static modifier in this case says that the nested class is a static member of the outer class. That means it can be accessed, as with other static members, without having an instance of the outer class.



public class OuterClass {

    static class NestedStaticClass {

        void go() {
            System.out.println("In nested static class");
        }
    }

    public static void main(String[] args) {
        OuterClass.NestedStaticClass n = new OuterClass.NestedStaticClass(); // both class names
        n.go();
    }
}

Syntax to create instance for static nested class:
OuterClass.NestedStaticClass n = new OuterClass.NestedStaticClass(); 

Since the nested class is static, it does not share any special relationship with an instance of the outer class and cannot access non-static members of the outer class.

Hope you liked the article. Join at +Java Territory to stay updated.

0 comments:

Post a Comment