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

时间:2010-05-14 02:19:20

标签: 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());
    }
}

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

我只看到一个普通的super(args)用于调用超类构造函数,而super.method()用于调用重写方法的超类版本,但是从来没有形式instance.super()。< / p>

5 个答案:

答案 0 :(得分:11)

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

引自here

  

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

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

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

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

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

  •     
  

答案 1 :(得分: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());
    }
}

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

答案 2 :(得分: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();
    }
}

打印:

Outer
OuterInner
OuterInnerChild
ONE MILLION DOLLAR!!!
Outer
OuterChild

一些重要的观察结果:

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

  

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

现在这是特定于内部类语义的:它是为了确保OuterInnerChild的所有实例都有Outer的{​​{1}}实例,Outer.Inner的超类。 。否则,OuterInnerChild的构造函数将没有Outer.Inner的封闭实例来调用Outer

答案 3 :(得分:2)

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

这就是为什么我们有像instance.new Inner()instance.super()这样有趣的语法 - 对于问题的回答“而 <{em> Inner?”isn'的上下文t立即显而易见。 (在外部类的非静态方法中,您可以说new Inner(),并且像往常一样this.new Inner()的缩写。)

答案 4 :(得分:0)

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