Inner Classes

Inner classes let you define one class within another, they provide a type of scoping for your classes since you can make one class a member of another class. This web page discusses four types of inner class

Inner Class

Normally when you are programming a class should have code only for the things an object of that particular type needs to do, any other behavior should be part of another class better suited for that job. Sometimes though you design a class that has different behavior but also needs to be intimately tied to the class you're designing, for an example event handlers are best example of this. One of the key benefits of an inner class is the "special-relationship" an inner class instance shares with an instance of the outer class. That special-relationship gives code in the inner class access to members of the enclosing (outer) class, as if the inner class was a part of the outer class, this includes any private members as well. Inner classes are not static, method-local or anonymous they are just a regular class.

Inner Class

class OuterClass {
   class InnerClass { }
}

Note: compiling the above will produce the below two files, you cannot run the OuterClass$InnerClass because a inner class cannot have a static declaration of any kind, you can only access the Inner class via the outer class.

OuterClass.class
OuterClass$InnerClass.class

Accessing private variables

class OuterClass {
   private int x = 75;

   public void makeInner() {
      InnerClass in1 = new InnerClass;
      in1.seeOuter();
   
   // Inner Class    
   class InnerClass {
      public void seeOuter() {
         System.out.println("Private variable x is " + x);
      }
   }
}

Note: we can access the private member with no problems which is perfectly legal

The only rules regarding inner classes is that you must have an instance of the outer class to tie to the inner class. A inner class can accept the following access modifiers: final, abstract, public, private, protected, static and strictfp.

create a inner class object from outside the outer class instance

public static void main (String[ ] args) {
   OuterClass mo = new OuterClass();
   OuterClass.InnerClass inner = mo.new InnerClass();

   // you could replace the above code with one line
   // OuterClass.InnerClass inner = new OuterClass().new InnerClass();

  inner.methodA();

}

referencing the Inner or Outer instance from within the inner class

class OuterClass {
   int count = 10;             // the outer class variable

   class InnerClass {
      int count = 5;           // the inner class variable

      void methodA() {
         System.out.println("inner count " + this.count);               // displays 5
         System.out.println("outer count " + OuterClass.this.count);    // displays 10
      }
   }
}

Method-Local Inner Class

A regular inner class is scoped inside another class curly braces, but outside any method code (in other words at the same level as instance variable is declared), but you can also define an inner class within a method.

Method-Local Inner class

class OuterClass2 {
   private String x = "OuterClass2";

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

      // You can only instantiate from within the method
      InnerClass ic = new InnerClass();     // This line must come after the class line
      ic.seeOuter();
   }
}

Method-Local inner classes can only be instantiated from within the method where the inner class is defined (no where else). The inner class has no access to the local method variables because when the method completes all local variables are destroyed, but even after the method has gone the class may still be around and with no local method variables this would cause problems, however if the local variables are marked final then the class can use them.

Anonymous Inner Class

Anonymous Inner class are what they say they are class without a name, you can declare them within a method or as a argument to a method.

Anonymous Inner Class
(flavor one)

class TestFood {
   public static void main(String [] args) {
      Food f1 = new Food();
      f1.p.pop();               // p is the anonymous class
   }
}

class PopCorn {
   public void pop() {
      System.out.println("pop goes the corn");
   }
}

class Food {
   Popcorn p = new PopCorn() {   // Notice no semi-colon but a backet instead, the start of the anonymous inner class
      public void pop() {        // override the superclass PopCorn's op method
         System.out.println("anonymous popcorn");
      }
   };   // end of the anonymous class, note the semi-colon
}

Note: the anonymous class is of type subclass

Anonymous Inner Class
(flavor two)

interface Cookable {
   public void cook();
}

class Food {
   Cookable c = new Cookable() {     // looks like you are instantiated a interface (not possible)
      public void cook() {
         System.out.println("anonymous Cookable implementer");
      }
   };
}

Note: the anonymous class is of type interface, also you can only implement one interface

Anonymous Inner Class
(flavor three)

class MyWonderfulClass {
   void go() {
      Bar b = new Bar();
      b.doStuff(new Foo() {             // implement the anonymous class as an argument
         public void foof() {
            System.outprintln("Foo interface implemented by annoymous class");
         }
      });   // end inner class def, argument and statement
   }
}

interface Foo {
   void Foo();
}

class Bar {
   void doStuff(Foo f) { ... }
}

When using anonymous inner classes polymorphism is in play, you can only call methods on an anonymous inner class reference that are defined in the reference variable type, this is no different from any other polymorphic reference. Anonymous inner classes can only be of one type either a subclass or interface type.

One final note is that when anonymous classes are created the filename is usually something like Class$1.class, Class$2.class, etc

Static Nested Class

Static nested classes are sometimes refered to as static inner classes, they aren't inner classes at all, by the standard definition of an inner class. A static nested class does not have that special-relationship that inner classes have, they cannot access the instance methods or variables. The class is not static (a class cannot be static), 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.

Static Nested Class public class OuterClass {
   static class Nested { ... }
}
Instantiating a Static Nested Class

class OuterClass {
   static class Nested { ... }
}

class TestClass {
   public static void main(String [] args) {
      OuterClass.Nested n = new OuterClass.Nested();
   }
}