Java: Inner Classes

Since Java 1.1, when inner classes were first introduced, they have started a lot of discussion. Some people like them and find them useful. Others hate them. Viewpoints apart, the fact is that inner classes can be efficient in many situations and it is possible to write clean code using them.

Basically, inner classes give us the possibility to define one class within another. In general, we divide classes in four groups:

  • Inner classes
  • Anonymous inner classes
  • Method-local inner classes
  • Static inner classes

Examples showed on this post were built using a JDK 6.

Inner Classes

Inner classes are mostly used when some pieces of the code are intimately tied. A chat application is a good example. When someone is chatting, the application needs to handle a couple of things in background, like, listening and writing into sockets, reading messages from text fields, sending messages when the “Send” button is pressed, and so on. The handlers (the Java components that help us to send and receive messages) are strongly tied to specific instances of the chat client’s components. These handlers need to access members of a specific component instance, like buttons, text fields, etc. Thus, we tend to implement these handlers as inner classes such  way they share a special relationship with its outer class instance. As the inner class is part of the outer class, it can access the private members of its outer class.

Following an example of an inner class.

public class OuterClass {
    private int index = 0;

    class InnerClass {
        public void printIndex() {
            // Because the inner class is a member of the
            // outer class, it can access its private members
            System.out.println("Index: " + index);
        }
    }
}

Compiling the above example will produce two class files:

OuterClass.class
OuterClass$InnerClass.class

The inner class has its own class file. Nevertheless, it is not possible to execute the inner class file in the usual way by doing java OuterClass$InnerClass.  Because a simple inner class cannot have static declarations, it is not possible to put a main method on it.

The only way to access inner classes members is through an instance of the outer class. This is only possible at runtime when there is an instance of the inner class tied to its outer class. In other words, an inner class instance cannot stand alone without an outer class instance.

Following an example of an outer class using an inner class.

public class MyOuterClass {
    private int index = 0;

    public void usingInnerClass() {
        // The only way to access MyInnerClass instance is
        // through MyOuterClass instance.
        MyInnerClass innerClass = new MyInnerClass();
        innerClass.printIndex();
    }

    class MyInnerClass {
        public void printIndex() {
            // Because the inner class is a member of the
            // outer class, it can access its private members.
            System.out.println("Index: " + index);
        }
    }
}

But, it is also possible to call methods of inner classes directly from a static context. As every inner class instance is tied to its outer class instance, we need an outer class instance for this. Let’s see an example:

public class InnerClassAcessor {
    public static void main(String... args) {
        MyOuterClass.MyInnerClass myInnerClass = new MyOuterClass().new MyInnerClass();
        myInnerClass.printIndex(); // will print Index: 0
    }
}

Is this magic? No, it’s only the keyword new called from a class instance. Instantiating an inner class is the only case in which we can call new on an instance, rather than invoking new to construct an instance. This is a special way to instantiate inner class from outside the class it lives in.

Finally, since the keyword this always refers to the current object instance, the same keyword used within an inner class refers to the instance of the inner class itself. So, when an inner class needs to refer to a member of the outer class, it needs to use the NameOfTheOuterClass followed by .this.

public class SecondOuterClass {
    private String classAlias = "outer alias";

    class InnerClass {
        String classAlias = "inner alias";

        public void printAlias() {
            System.out.println("Outer: " + SecondOuterClass.this.classAlias);
            System.out.println("Inner: " + this.classAlias);
        }
    }

    public static void main(String... args) {
        InnerClass innerClass = new SecondOuterClass().new InnerClass();
        innerClass.printAlias();    // will print   Outer: outer alias
                                    //              Inner: inner alias
    }
}

Anonymous inner classes

Anonymous inner classes are called “anonymous” because they don’t have a class name. Anonymous inner classes can be used in many situations: inside a method, as a class member or even as a method argument.

Following an example of anonymous inner class defined inside a method.

abstract class Bird {
    abstract void fly();
}

public class AnonymousInnerClass {
    public static void main(String... args) {
        Bird bird = new Bird() {
            @Override
            void fly() {
                System.out.println("Flying...");
            }
        };  // Semicolon required!

        bird.fly(); // Will print Flying...
    }
}

It is important to remark that when using anonymous inner classes as a class member or a local variable inside a method, the semicolon is required at the end of the class instantiation. If the semicolon is omitted the code does not compile.

Anonymous inner classes are available in two flavors. The first one is called anonymous subclass. Anonymous subclasses are created extending a class. The second flavor is called anonymous implementer and is created when implementing anonymously an interface.

Another point to be mentioned is that methods defined inside anonymous inner classes other those overridden from the super class or the interface cannot be called from the outside. Since Java is a strongly typed language, only methods defined by the type can be called. 

Method-local inner classes

Simple inner classes are defined inside a class, more specifically inside the curly braces of a class. Method-local inner classes are inner classes defined inside methods and can be used only with the method they are defined in. There is no other piece of code (inside another method or class) that can instantiate a method-local inner class.

public class MethodLocalInnerClass {
    private int x = 10;

    void printFromInner() {
        class InnerClass {
            public void printX() {
                System.out.println("x=" + x);
            }
        }

        InnerClass innerClass = new InnerClass(); // must come after the class
        innerClass.printX();
    }
}

On the other hand, there is an interesting point here: method-local inner classes cannot access the local variables of the method the inner class was defined in (trying this will produce a compiler error). The reason is simple: as the local variables of the method live in the stack, they exist only during the method execution lifetime. So, if an instance of a method-local inner class is passed to another class and it is being used there, when the method ends, its local variables don’t exist anymore. The only way to use method-local variables inside method-local inner classes is declaring them final. Once it has been assigned, the value of the final variable cannot change. This allows the Java compiler to “capture” the value of the variable at runtime and store a copy as a field in the inner class.

class MethodLocalInnerClass2 {
    private int x = 10;

    public static void main(String... args) {
        MethodLocalInnerClass2 clazz = new MethodLocalInnerClass2();
        clazz.printFromInner(); // will print x=101
    }

    void printFromInner() {
        final int y = 1;
        class InnerClass {
            public void printX() {
                System.out.println("x=" + x + y);
            }
        }

        InnerClass innerClass = new InnerClass(); // must come after the class
        innerClass.printX();
    }
}

And only to remember, local variables rules are also applied to method-local inner classes and they cannot be declared public, private, static, protected, transient, etc. Only abstract and final are allowed.

This question on stackoverflow brings some good examples about the use of method-local inner classes.

Static inner classes

Static inner classes or static nested classes are members of the outer class that can be accessed from a static context. In this case, static inner classes can be accessed like any other static member, without having an instance of the outer class.

On the other hand, there is also another point with static inner classes. Unlike the other inner classes, static inner classes don’t have any kind of special relationship with the outer class, except the namespace. In other words, they cannot access non-static members of the outer class.

class HelperClass {
    static class InnerHelper {
        void print() {
            doPrint();
        }
    }

    static void doPrint() {
        System.out.println("Printing from HelperClass");
    }
}

public class StaticInnerClassExample {
    static class AnotherHelper {
        void print() {
            System.out.println("Printing from AnotherHelper");
        }
    }

    public static void main(String... args) {
        /* Remark the way we create an instance of a static inner class
         is not the same as for inner classes */
        HelperClass.InnerHelper h1 = new HelperClass.InnerHelper();
        h1.print(); // will print: Printing from HelperClass
        AnotherHelper h2 = new AnotherHelper();
        h2.print(); // will print: Printing from AnotherHelper
    }
}

Note: A non-static nested class (or “inner class”) has full access to the members of the class within which it is nested. A static nested class does not have a reference to a nesting instance, so a static nested class cannot invoke non-static methods or access non-static fields of an instance of the class within which it is nested.

Advertisements

About Diego Lemos

Trainer, coach and polyglot programmer. Agile and software craftsmanship enthusiast.
This entry was posted in Java and tagged , . Bookmark the permalink.

One Response to Java: Inner Classes

  1. Pingback: Back to Basics : Bien maîtriser les classes internes en Java | Blog Xebia France

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s