为什么内部类的子类需要封闭实例?

a.a*_*ous 8 java inheritance inner-classes

考虑OuterClass有的课程InnerClass

public class OuterClass {
    class InnerClass {

    }
}
Run Code Online (Sandbox Code Playgroud)

而第二类,它正试图延长InnerClassOuterClass

public class Clazz extends OuterClass.InnerClass {
    public Clazz(OuterClass outerClass) {
        outerClass.super();
    }
}
Run Code Online (Sandbox Code Playgroud)

到目前为止这么好,这段代码会起作用,编译器不应该发出警告.

但我试图理解 - 为什么有必要传递给OuterClass的构造函数引用?为什么有必要称它为超级构造函数?

我想明白为什么它必须这样精确?

另外,还要考虑这个类(不涉及以前的),其中的类ApartmentsHall有内部类Building类,这是内蒙古自治区Solution(innerception).

public class Solution {
    public class Building {
        public class Hall {
            private BigDecimal square;

            public Hall(BigDecimal square) {
                this.square = square;
            }
        }

        public class Apartments {
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后是顶级课程,试图扩展内部的内部堂堂

class BigHall extends Solution.Building.Hall {
    public BigHall(Solution.Building building, BigDecimal square)
    {
        building.super(square);
    }
}
Run Code Online (Sandbox Code Playgroud)

看看这个烂摊子.最后两个类也应该编译,但是你可以为我清理它,为什么BigHall类在扩展内部内部类时Hall确实需要传递给构造对象而不是Solution对象?

如果你能提供JLS的报价那就太好了!

Sot*_*lis 7

InnerClass是一个内心阶级.

一个内部类是没有明确或隐含声明的嵌套类static.

内部类可能包含实例

一个实例i的直接内部类的C [您InnerClass]的类或接口的O [您OuterClass]与实例相关联的O,被称为的立即封闭实例i.

只有在静态上下文中声明的内部类才没有封闭实例.

I声明在静态上下文中发生的内部类的实例没有词法封闭的实例.

您的示例的内部类不在静态上下文中,因此需要一个封闭的实例.

然后,Java语言规范说明

非私有内部成员类的构造函数隐式声明,作为第一个形式参数,表示该类的直接封闭实例的变量

(如果你感兴趣,它会进一步详细说明原因).换句话说,你的InnerClass构造函数看起来很像

public InnerClass(OuterClass OuterClass.this){} // this is valid syntax for entirely different reasons
Run Code Online (Sandbox Code Playgroud)

它期望OuterClass使用类型的参数作为其封闭实例.对此InnerClass类型进行子类化不会改变这种情况,特别是因为任何子类型都必须调用其超类型的超级构造函数.

关于构造函数的主题,规范也指出

如果构造函数体不以显式构造函数调用开始并且声明的构造函数不是原始类的一部分Object,则构造函数体隐式地以超类构造函数调用"super();"开头.,调用其直接超类的构造函数,不带参数.

显然,如果没有参数,您的代码将无法正常工作

public class Clazz extends OuterClass.InnerClass {
    public Clazz() {
        // implicit super() invocation
    }
}
Run Code Online (Sandbox Code Playgroud)

super()构造函数调用不起作用.在这种情况下,这是因为它是错误的语法.但是这个想法是超级构造函数期望表示封闭实例的形式参数的参数,但是你没有提供.正确的语法是您已有的语法.我们来定义它.

多种构造函数调用.你的

public Clazz(OuterClass outerClass) {
    outerClass.super();
}
Run Code Online (Sandbox Code Playgroud)

是一个限定的超类构造函数调用,定义

合格的超类构造函数调用Primary 表达式或表达式开头ExpressionName.它们允许子类构造函数显式指定新创建的对象关于直接超类(第8.1.3节)的直接封闭实例.当超类是内部类时,这可能是必要的.

去一个解释的表达是如何计算

如果超类构造函数调用是合格的,那么将计算 Primary表达式或ExpressionName紧接在前的" .super" p.
[...]

否则,本次评测的结果是立即封闭实例i相对于S.

换句话说,通过引用的对象outerClass变成所需的外围实例您的Clazz实例.


简单来说,忽略内部类的情况,你的例子归结为类似的东西

public class Foo {}
public class Bar {
    public Bar(Foo foo){}
}
public class SubBar extends Bar {
    public SubBar(Foo foo) {
        super(foo);
    }
}
Run Code Online (Sandbox Code Playgroud)

SubBar必须满足Bar期望Foo实例的超级构造函数.Clazz除了超类型的构造函数是隐式的之外,这与你的类型一样.