Search code examples
javaclassstaticnew-operator

Java new keyword with static inner class


I know this questions has been asked before, but mostly pretty specific regarding a certain library. And the answers given didn't really explain to me what was going on.

That's why I set up a pretty simple test scenario here, and tried to fiddle with it, but there are still some question marks! Online Java Example

The simple code consists of two files:

Main.java

public class Main
{
    public static void main(String[] args) {
        // this works, and inner1 and inner2 seem to be new instances
        Outer.Inner inner1 = new Outer.Inner();
        Outer.Inner inner2 = new Outer.Inner();
        inner1.setName("Mario");
        inner1.say();
        inner2.setName("Luigi");
        inner2.say();

        // if Inner is not a public static class this gives this error:
        // error: an enclosing instance that contains Outer.InnerNoStatic is required
        Outer.InnerNoStatic inner3 = new Outer.InnerNoStatic();
    }
}

Outer.java

public class Outer {
    public static class Inner {
        private String name;

        public void say() {
            System.out.println("Hi " + name);
        }

        public void setName(String name) {
            this.name = name;
        }
    }

    public class InnerNoStatic {
        public void say() {
            System.out.println("Hi from InnerNoStatic");
        }
    }
}

So it seems like even though the Inner class is declared with static, we create two new instances called inner1 and inner2. Why is it called static then?

And in turn, if I remove the static, as in InnerNoStatic how would I go about getting an instance of that class?


Solution

  • static here dictates how Inner and InnerNoStatic are used with respect to Outer.

    Because Inner is static in Outer, it is not tied to any specific instance of Outer (as always, a static member belongs to the class, not to any particular instance of that class). That explains how this compiles:

    Outer.Inner inner1 = new Outer.Inner();
    

    InnerNoStatic, however, is an instance member (that's that: if it's not static, it is tied to a given member). And that explains why the compiler raises an error here:

    Outer.InnerNoStatic inner3 = new Outer.InnerNoStatic();
    

    Because InnerNoStatic must be tied to an instance of Outer, you need to use such an instance to create inner3:

    Outer.InnerNoStatic inner3 = new Outer().new InnerNoStatic(); //note the calls
    

    Your can also use an existing instance.

    Outer outer = new Outer();
    Outer.InnerNoStatic inner3 = outer.new InnerNoStatic();
    

    In both of these cases, an Outer instance is used to build an InnerNoStatic instance (there's just no variable pointing to the Outer object created with new Outer().new InnerNoStatic())


    Note: It's easy to confuse new Outer.Inner(); with new Outer().new Inner();. These are not doing the same thing ("Outer" in the former is basically playing the role of a namespace, whereas new Outer() in the latter is creating an Outer object). That is, one constructor call (Inner()) in the former, but two constructor calls in the latter (Outer() and Inner()).