Why can't outer classes extend inner classes?

前端 未结 2 1445
半阙折子戏
半阙折子戏 2021-02-09 05:44

Why can\'t I do this/is there a workaround to accomplish this:

package myPackage;

public class A {
    public class B {

    }
}



        
2条回答
  •  北恋
    北恋 (楼主)
    2021-02-09 06:27

    Well, it can be done, but you have to remember that each constructor needs to call its super constructor, explicitly or implicitly. That's why you get the "No enclosing instance of type A is available due to some intermediate constructor invocation" error. C's no-args constructor is trying to implicitly call B's no-args constructor, and it can't do that without an A.

    So you fix your C to be:

    public class C extends B {
        public C(A enclosing) {
            enclosing.super();
        }
    }
    

    And then you can create a new C by using:

    A myA = new A();
    C myC = new C(myA);
    

    Answers to the questions in the comments

    • @Andi Turner asked:

      If you are explicitly passing in an A to the constructor of C, can't C now be static, and have A as a "plain old" member variable in C on which you invoke the required methods?

      It should be noted that C is neither static nor an inner class. It is an individual public class which is extending an inner class B. The implementation of the class B may not be known to the author of C, so it cannot know what methods would be using A, nor does it have access to any private members of A, as C is not a member of A. But B does, and B requires the A instance. An alternative approach would be composition rather than inheritance (where C holds a B instance and delegates operations to it), but if it wants to create that B instance rather than have it passed inside, it will still need an A instance, although it will use enclosing.new B rather than enclosing.super.

    • @rajuGT asked:

      Is C is an individual entity? if so, why does it need A object? and what is the association between myA and myC in this case?

      Yes, C is an individual entity. It wouldn't need A for any of its own methods. But if it tries to call (or inherits and doesn't override) methods from B that involve access to A - then that A is required by the implementation of B. Formally, of course, any instance of B requires a reference to A even if it doesn't actually make use of it. The association between myA and myC are is that myA is the immediate enclosing instance of myC with respect to B. This term is taken from section 8.1.3 of the JLS:

      For every superclass S of C which is itself a direct inner class of a class or interface SO, there is an instance of SO associated with i, known as the immediately enclosing instance of i with respect to S. The immediately enclosing instance of an object with respect to its class' direct superclass, if any, is determined when the superclass constructor is invoked via an explicit constructor invocation statement (§8.8.7.1)

    Official reference for this usage

    This usage is known as a qualified superclass constructor invocation statement, and is mentioned in the JLS, section 8.8.7.1 - Explicit Constructor Invocations.

    Superclass constructor invocations begin with either the keyword super (possibly prefaced with explicit type arguments) or a Primary expression or an ExpressionName. They are used to invoke a constructor of the direct superclass. They are further divided:

    • Unqualified superclass constructor invocations begin with the keyword super (possibly prefaced with explicit type arguments).

    • Qualified superclass constructor invocations begin with a Primary expression or an ExpressionName. They allow a subclass constructor to explicitly specify the newly created object's immediately enclosing instance with respect to the direct superclass (§8.1.3). This may be necessary when the superclass is an inner class.

    At the end of that section, you can find examples for explicit constructor invocation statements, including this usage.

提交回复
热议问题