Inner classes offer are a powerful extension to Java’s object model. However, the syntax for some of the more advanced features of member inner classes is quite tricky to get to grips with. In a previous article, I discussed the different types of inner classes along with a demonstration of how they are most commonly used. In this article I’ll explain the full details of the inner class syntax in Java.

The basics

To define an inner class, just define one class within another:

public class Outer {
    public class Inner {

    }
}

Generally, the outer class will be responsible for creating instances of the inner classes and this could be done in the methods of the outer class, for example here where the outerClassesMethod creates an inner class instance and calls its method (lines 7-8) :

public class Outer {

    private String message = "foo";

    public void outerClassesMethod() {
        //create an inner object to do the work
        Inner ii = new Inner();
        ii.innerClassesMethod();
    }

    private class Inner {
        private void innerClassesMethod() {
            System.out.println(message);
        }
    }
}

Note above that the inner classes method (line 12), although private, can still be called by the outer class. Also note that the private message field on the outer class (line 3) can be accessed from the inner class. A call to the outerClassesMethod will cause the innerClassesMethod to be called and the message ‘foo‘ to be printed to std out.

What about ‘this’ ?

Each object in a Java application can refer to itself using the ‘this’ reference. When an instance of an inner class is created, it is created within the instance that created it; so what effect does this have on ‘this’ reference?

In fact, inner class instances have more than one ‘this’ reference: one that refers to the instance of the inner instance, and one that refers to the outer instance. Consider this simple change to the example:

public class Outer {

    private String message = "foo";

    public void outerClassesMethod() {
        //create an inner object to do the work
        Inner ii = new Inner();
        ii.innerClassesMethod();
    }

    private class Inner {
        private String message = "bar";

        private void innerClassesMethod() {
            System.out.println(message);
        }
    }
}

Now that the inner class also has a field named message, the text ‘bar‘ will be printed out instead of ‘foo’.

The reason for this is that the inner classes message field has shadowed the outer classes one. The inner classes println call (line 15) would have the exact same behaviour if it were written as:

System.out.println(this.message);

if we want to access the message field on the outer class, then we need to use a ‘this’ reference for the outer instance; we do this by pre-pending the class name to ‘this’ as follows:

System.out.println(Outer.this.message);

substituting the println statement with the one shown above, will access the message field on the Outer class and cause ‘foo‘ to be printed out once again.

Creating inner instances from outside the outer class

As noted above, the inner instances will generally be created within the outer class. However, it is possible for inner instances to be created in other places too; for example, a factory class could be used to create the outer objects and also the inner objects that they will contain.

To demonstrate this scenario, we’ll use a slightly revised example where the inner class, and its method, have been made publicly visible. Note also that the outer class now has a constructor (lines 4-6) that will allow us to initialise its private message field (line 3) :

public class Outer {

    private String message;

    public Outer(String message) {
        this.message = message;
    }

    public class Inner {
        public void innerClassesMethod() {
            System.out.println(message);
        }
    }
}

If our factory class is to create the inner class instances, then it must associate them with an outer instance. In order to do this the new keyword must be scoped to a particular outer instance using this somewhat cumbersome syntax:

Outer o = new Outer("foo");
Outer.Inner i = o.new Inner();
i.innerClassesMethod();

Note the use of the new keyword (line 2) is prepended with the outer object reference (i.e. o.new). It is this outer reference that will be accessible within the inner object’s methods using the ‘this’ syntax explained above.

So, when the call to the inner classes method is made (on line 3), the private message field of the outer instance will be printed out – i.e. we’ll see ‘foo‘ appear in std out.

Static inner classes

The static modifier can be applied to member level classes in much the same was as it can with the fields and methods of that class. As with fields and methods, use of the static modifier pretty much turns off OO.

public class Outer {

    private String message;

    static class Inner {
        private String message;

        public void innerClassesMethod() {
            //can access the message field defined on this class:
            System.out.println(this.message);

            //can't access the one from the outer class though:
            System.out.println(Outer.this.message);
        }
    }
}

In much the same way as a static method is not associated with an object instance, objects created from static inner class definitions are not associated with an outer object instance either.

Static inner classes therefore do not have a second this reference, and cannot access the non-static fields of the outer class (line 13 in the above example would produce a compiler error). Effectively, inner classes are just regular classes defined within an outer classes name-space.