I have recently tried one Java quiz and there was a question about class nesting. I didn’t answer correclty since I hardly ever use this language feature and when use I nested classes, I use them somewhat intuitively.

Let’s refresh this piece of knowledge and add some remarks.

Java allows to declare a class inside another class.
It’s a way how to group together classes that are used only in one place.
Use this technique when you have for example a helper class used only by one client class.
In that case, embed the helper inside the client.

There are two types of nesting:

  • Static nested classes
  • Inner classes

Static Nested Class

Static Nested Class
public class OuterClass {
    static class StaticClass { 1
        public void foo() {
            System.out.println("Foo!");
        }
    }
}
  1. Standard access modifiers are used: public, private, protected, package private

Basically, it is a top-level class, just declared inside another class instead of a package.
Naturally, it cannot access instance members of its outer class. A static class can be accessed through the class reference, i.e. OuterClass.StaticClass.

You can create an instance of such class outside the outer class.

Instantiating the Nested Static Class
public class AnotherClass {
    public void callStaticClass() {
        OuterClass.StaticClass staticClassInst = new OuterClass.StaticClass();
    }
}

Inner Class

An inner is associated with its outer class' instance.
It can access instance members of its outer class.
You cannot declare static members in an inner class. Special cases of inner classes are local and anonymous classes.

Inner Class
class OuterClass {

    private int outerInt = 666;

    class InnerClass {
        public void bar() {
            System.out.println("Bar! " + outerInt);
        }
    }

    public void useInnerClass() {
        new InnerClass().bar(); // Will print Bar! 666
    }
}

The inner class can be instantiated also outside the outer class declaration. The syntax is a little funkier since we need the instance of the outer class to do so.

Instantiating the Inner Class
OuterClass outer = new OuterClass();
OuterClass.InnerClass inner = outer.new InnerClass();

Shadowing

In the following example, you can see that there is an integer value declared in both Wrapper and Inner class. Let’s demonstrate how the value is shadowed locally (quite a basic Java principle)

Shadowing example
class WrapperClass {

    private int value = 0;

    class Inner {
        private int value = 10;

        void printValue(int value) {
            System.out.println("value: " + value);
            System.out.println("this.value: " + this.value);
            System.out.println("WrapperClass.this.value: " + WrapperClass.this.value);
        }
    }

    public static void main(String[] args) {
        WrapperClass wc = new WrapperClass();
        WrapperClass.Inner inner = wc.new InnerClass();

        /*
            Will print
            value: 123
            this.value: 10
            WrapperClass.this.value: 0
        */
        inner.printValue(123);
    }

}

We can see how to access the 'this' of a wrapping instance.

I can imagine a JavaScript developer would see a similarity to closures. You can encapsulate some context in a wrapping class and then present an object that uses such context as an instance of nested class. Now, I must examine if this is used somewhere as a pattern or not (article possibly comming soon).

Wrap Up

So, this was a quick introduction to nested classes.
Personally, I am not really enthusiastic about them (except for anonymous classes written as lambdas).
It might be that I haven’t seen them used correctly but when I read pieces of code with inner/local/anonymous classes, the class declarations usually broke the code flow and made the code harder to read. See for example this Oracle Tutorial about Local Classes

I understand that when a class is used only once, it is good to keep its source code as close as possible to the place of its usage, but the cost is to have several lines of "alien" code written inside my code (hello, anonymous classes).
Another question is testability of inner classes, that is an important point to consider.

Like it or not, it’s important to know that Java offers this language construct and even if you don’t use the nested classes actively, you should not be surprised when you come across them.