Java:非静态嵌套类和instance.super()

我很难在Java中围绕非静态嵌套类。 考虑以下示例,其中打印“内部”然后打印“子”。

class Outer { class Inner { Inner() { System.out.println("Inner"); } } } public class Child extends Outer.Inner { Child(Outer o) { o.super(); System.out.println("Child"); } public static void main(String args[]) { new Child(new Outer()); } } 

我理解Inner的实例总是必须与外部实例相关联,并且它也适用于Child,因为它扩展了Inner。 我的问题是o.super()语法的含义 – 为什么它调用Inner构造函数?

我只看到一个普通的super(args)用于调用超类构造函数和super.method()来调用重写方法的超类版本,但从来没有forms为instance.super()

它被称为“合格的超类构造函数调用”。

引自这里 :

显式构造函数调用语句可以分为两种:

  • 替代构造函数调用以关键字this开头(可能以显式类型参数开头)。 它们用于调用同一类的备用构造函数。

  • 超类构造函数调用以关键字super(可能以显式类型参数开头)或Primary表达式开头。 它们用于调用直接超类的构造函数。 超类构造函数调用可以进一步细分:

  • 非限定的超类构造函数调用以关键字super开头(可能以显式类型参数开头)。

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

内部类(非静态子类)本质上是嵌套类(静态子类),其隐式链接返回其父对象。 以下是您使用静态嵌套类编写的上述代码:

 class Outer { static class Inner { final Outer outer; Inner(Outer outer) { this.outer = outer; System.out.println("Inner"); } } } public class Child extends Outer.Inner { Child(Outer o) { super(o); // o.super(); System.out.println("Child"); } public static void main(String args[]) { new Child(new Outer()); } } 

看看这个,你应该能够理解o.super()正在做什么。

为什么Child中的o.super()最终会调用Outer.Inner构造函数? 这很简单:因为Child extends Outer.Inner ,并且构造函数调用总是链接到层次结构中。

以下是对您的代码段的轻微扩展,以说明:

 class Outer { Outer() { System.out.println("Outer"); } void outerMethod() { } class Inner { Inner() { System.out.println("OuterInner"); outerMethod(); } String wealth; } } class OuterChild extends Outer { OuterChild() { System.out.println("OuterChild"); } } public class OuterInnerChild extends Outer.Inner { OuterInnerChild(Outer o) { o.super(); System.out.println("OuterInnerChild"); this.wealth = "ONE MILLION DOLLAR!!!"; } public static void main(String args[]) { System.out.println(new OuterInnerChild(new Outer()).wealth); new OuterChild(); } } 

这打印:

 Outer OuterInner OuterInnerChild ONE MILLION DOLLAR!!! Outer OuterChild 

一些重要观察:

  • 因为OuterInnerChild extends Outer.Inner ,它inheritance了wealth ,就像普通的子类语义一样
    • 就像普通的子类语义一样, OuterInnerChild的构造OuterInnerChild链到OuterInnerChild的构造Outer.Inner
  • 因为OuterChild extends Outer ,它的构造函数链,即使没有显式调用
    • 无论是隐式还是显式,构造函数都会链接层次结构

但是为什么编译器要求OuterInnerChild构造函数采用Outer o ,并调用o.super()

现在这是特定于内部类语义的:它是为了确保OuterInnerChild所有实例都有一个OuterInnerChildOuter实例,即Outer.Inner的超类。 否则, Outer.Inner的构造Outer.Inner将没有Outer的封闭实例来调用outerMethod()

从概念上讲,非静态内部类“属于”特定对象。 有点像每个人都有自己的类版本,就像非静态字段或方法属于特定对象一样。

所以这就是为什么我们有一些有趣的语法,比如instance.new Inner()instance.super() – 对于上下文,问题的答案“但 Inner ?”并不是很明显。 (在外部类的非静态方法中,你可以说new Inner() ,并且像往常那样是this.new Inner()的缩写。)

总是不要忘记基本原则,在调用子类构造函数的过程中,无论内部/外部类如何,它总是首先实例化父类。 在您的场景中,当您扩展内部类时,您的内部类是父类的成员,需要实例化,然后调用实际的内部类构造函数。