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

Kiv*_*Kiv 17 java inner-classes

我很难在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());
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

Art*_*cto 11

它被称为"合格的超类构造函数调用".

引自这里:

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

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

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

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

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


Gun*_*r47 10

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

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());
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 事实上,根据我的理解,非静态内部类基本上是上面的语法糖. (2认同)
  • 好吧,对.我只是说一个*非静态*内部类是句法糖之上的语法糖:-D (2认同)

pol*_*nts 6

为什么o.super()Child结束了调用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();
    }
}
Run Code Online (Sandbox Code Playgroud)

这打印:

Outer
OuterInner
OuterInnerChild
ONE MILLION DOLLAR!!!
Outer
OuterChild
Run Code Online (Sandbox Code Playgroud)

一些重要观察:

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

但是为什么编译器要求OuterInnerChild构造函数接受一个Outer o,并且o.super()调用它?

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