The Java Qualified Superclass Constructor Invocation

Marcio EndoMarcio EndoJan 5, 2025

In Java, a nested class is a class declared within the body of another class. Nested classes can be either static or non-static. The non-static kind is commonly referred to as inner classes and maintain a special relationship with their enclosing class.

When a class extends an inner class, a specific syntax may be required in the constructor to provide the superclass's enclosing instance. This is what we'll discuss in this blog post.

Our Running Example

Let's start with the following class hierarchy:

public class Outer {  public class Inner {}}

Here, we've defined a top-level class named Outer, which contains an inner class named Inner. Next, let's declare a new class named Example:

public class Example extends Outer.Inner {  // Warning: does not compile!}

It is also a top-level class and attempts to extend the Inner class defined earlier. However, when we try to compile these classes, the compilation fails with the following error:

Example.java:1: error:
an enclosing instance that contains Outer.Inner is required

public class Example extends Outer.Inner {
       ^
1 error

The error message indicates that an enclosing instance of Outer is required. But how can we provide one?

Inner Classes

Before addressing the issue with our Example class, let's take a closer look at the error message. The same error occurs if we try to create an instance of Inner as though it were a static nested class:

// Warning: does not compile!Outer.Inner inner = new Outer.Inner();

When we compile this code along with the Outer class, the compilation fails with the following error:

Test.java:3: error:
an enclosing instance that contains Outer.Inner is required

    Outer.Inner inner = new Outer.Inner();
                        ^
1 error

Notice that the error message is identical to what we encountered earlier. Once again, it explicitly states that an enclosing instance of Outer is required.

To resolve this, we update the main method:

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

In the updated code:

  1. We create an instance of the enclosing class, Outer.

  2. Using this instance, we create an instance of the inner class, Inner.

Alternatively, this can be expressed in two separate statements:

Outer outer = new Outer();Outer.Inner inner = outer.new Inner();

Both approaches successfully compile. The key takeaway is that to create an instance of an inner class, you must first instantiate its enclosing class.

The Qualified Superclass Constructor Invocation

Let's return to our Example class. It is a subclass of Inner, an inner class. This means that an instance of Example is implicitly also an instance of Inner. Consequently, to create an instance of Example, we must first provide an instance of Outer.

Using a Primary Expression

One solution is to use a qualified superclass constructor invocation with a primary expression:

public class Example extends Outer.Inner {  Example() {    new Outer().super();      }}

In the Example constructor:

  1. We create an instance of Outer, the enclosing class of the superclass.

  2. Using this instance, we invoke the Example superclass constructor, which corresponds to the Inner constructor, via the super() call.

Let's see this in action. First, we update the Outer and Inner classes as follows:

public class Outer {  Outer() {    System.out.println("Outer()");  }  public class Inner {    Inner() {      System.out.println("Inner()");    }  }}

To observe the constructor invocation, we've added explicit constructors that print a message when invoked. Now, let's write a program to create an instance of the Example class:

void main() {  new Example();    }

When executed, the program prints:

Outer()
Inner()

In the Example constructor, we use a qualified superclass constructor invocation with a primary expression, new Outer(), to create and provide the required enclosing instance.

Using an Expression Name

Alternatively, we can pass an explicit Outer instance to the Example constructor:

public class Example extends Outer.Inner {  Example(Outer outer) {    outer.super();  }}

In this approach, we update the main method as follows:

void main() {  Outer outer = new Outer();      new Example(outer);}

This version of the program produces the same output:

Outer()
Inner()

By passing an explicit Outer instance, the super() call uses the provided instance to invoke the Inner constructor. Both approaches demonstrate how a qualified superclass constructor invocation provides the enclosing instance for the superclass of our Example class.

It's All in the JLS

What we've shown in the examples is explicitly defined in the Java Language Specification (JLS). In particular, Section 8.8.7.1, titled "Explicit Constructor Invocations," provides the following production:

ExplicitConstructorInvocation:
  [TypeArguments] this ( [ArgumentList] ) ;
  [TypeArguments] super ( [ArgumentList] ) ;
  ExpressionName . [TypeArguments] super ( [ArgumentList] ) ;
  Primary . [TypeArguments] super ( [ArgumentList] ) ;

Pay particular attention to the last two lines. They define how super() can be invoked either from an expression name or a primary expression.

Not Restricted to Top-Level Classes

An inner class must also use the qualified superclass constructor invocation in its constructor if it extends another inner class with a different enclosing type. To illustrate, let's first examine a scenario where the qualified superclass constructor invocation is not required:

public class Outer {  public class Inner {}  public class NotRequired extends Inner {}}

This compiles without errors. Here, the NotRequired class is:

  1. An inner class with respect to Outer.

  2. A direct subclass of Inner.

Since both NotRequired and Inner share the same enclosing class (Outer), their enclosing instances have the same type, and no special constructor invocation is needed.

Now, consider the following class hierarchy:

public class Outer {  public class Inner {}  public static class NewContext {    public class Required extends Inner {      Required() {        new Outer().super();      }    }  }}

In this example, although Required and Inner are both enclosed in Outer, their immediate enclosing classes differ. Specifically:

  • Inner is directly enclosed by Outer.

  • Required is directly enclosed by NewContext.

Since the enclosing instances of Required and Inner have different types, creating an instance of Required requires explicitly providing an instance of Outer, the enclosing class of its direct superclass.

Final Note

In the first example of the previous section, while the qualified superclass constructor invocation is not required, it is still allowed. This means the following code compiles without errors:

public class Outer {  public class Inner {}  public class NotRequired extends Inner {    NotRequired() {      new Outer().super();    }  }}

However, this version is semantically different from the original. In this case, the enclosing instance of NotRequired is a distinct, newly created Outer object.

Conclusion

In this blog post, we discussed the qualified superclass constructor invocation. This uncommon language construct is required when the superclass is an inner class; before invoking the superclass constructor, we must provide the enclosing instance of the superclass.

I haven't found uses of the qualified superclass constructor invocation in the wild. Granted, I've never looked for it specifically, but I don't remember seeing it in any of the code I've read.

I found this topic interesting enough to share, as it highlights a less commonly discussed corner of the language. However, unless you encounter a specific use case that demands this approach, I'd recommend avoiding it purely for novelty's sake. Simplicity and readability should remain priorities in your code.