Geek
Geek

Reputation: 27203

Why the call to the parent constructor is not the first call in the compiler generated constructor for Inner class?

Consider the following Test class to demonstrate the inner class behavior in Java. The main code is in the run method. Rest is just plumbing code.

 public class Test {

        private static Test instance = null;

        private Test() {
        }

        private void run() {
            new Sub().foo();  
        }

        public static void main(String[] args) {
            instance = new Test();
            instance.run();
        }

        class Super {
            protected void foo() {
                System.out.println("Test$Super.Foo");
            }
        }

        class Sub extends Super {
            public void foo() {
                System.out.println("Test$Sub.Foo");
                super.foo();
            }
        }
    }

I am just printing below the javap output for the hidden Sub constructor:

so.Test$Sub(so.Test);
    Code:
       0: aload_0       
       1: aload_1       
       2: putfield      #1                  // Field this$0:Lso/Test;
       5: aload_0       
       6: aload_1       
       7: invokespecial #2                  // Method so/Test$Super."<init>":(Lso/Test;)V
  10: return   

Normally the compiler ensures that the sub-class constructor would call into the super-class constructor first before going on to initialize its own fields. This aids in a correctly constructed object but I am seeing an aberration from the normative behavior in the case of the constructor that the compiler generates for an Inner class. Why so? Is it specified by JLS?

P.S: I know that the inner class contains a hidden reference to the outer class and that reference is being set here in the above javap output. But the question is why it is set before calling super constructor. What am I missing?

Upvotes: 2

Views: 93

Answers (1)

Rafael Winterhalter
Rafael Winterhalter

Reputation: 44042

An inner class is an abstraction that should be as transparent to a Java programmer as possible. Consider the following class structure and think about what would happen if you set the $this field only after calling the inner class's super constructor.

class Foo {
  Foo() { System.out.println(foo()); }

  String foo() { return "foo"; }
}

class Bar {
  String bar() { return "bar"; }

  class Qux extends Foo {
    @Override 
    String foo() { return bar(); }
  }
}

Note how the overridden method in class Qux calls a method of its outer class Bar. For this to work, the $this field that holds the Bar instance must be set before the super constructor of Foo is invoked. Otherwise, you would end up with a NullPointerException as the field is not yet initialized. To make this more clear, look at the following call chain of any instanciation of a Qux instance:

Qux() -> Foo() -> this.foo() -> $this.bar()

As a programmer that is not to familiar with the implementation of an inner class, you would wonder where this exception comes from. In order to make the inner class abstraction transparent, you must set the field first, otherwise you would be stuck with a quite leaky abstraction. I do not argue that this makes the above example a good implementation, but it is legal.

Upvotes: 1

Related Questions