代码之家  ›  专栏  ›  技术社区  ›  Kiv

JAVA:非静态嵌套类和实例.Suffor()

  •  17
  • Kiv  · 技术社区  · 15 年前

    我很难在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());
        }
    }
    

    我理解内在的实例总是必须与外部的实例相关联,这也适用于儿童,因为它扩展了内在。我的问题是 o.super() 语法意味着-为什么它调用内部构造函数?

    我只见过平原 super(args) 用于调用超类构造函数和 super.method() 调用重写方法的超类版本,但不调用窗体的某个内容 instance.super() .

    5 回复  |  直到 12 年前
        1
  •  11
  •   chepseskaf Nick Holt    12 年前

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

    引用来自 here :

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

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

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

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

    • 限定的超类构造函数调用从主表达式开始。它们允许子类构造函数针对直接超类(_§8.1.3)显式指定新创建的对象的立即封闭实例。当超类是内部类时,这可能是必需的。

        2
  •  10
  •   Boann    12 年前

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

    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()在做什么。

        3
  •  6
  •   polygenelubricants    15 年前

    为什么 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 链接到的构造函数 外部内部
    • 因为 OuterChild extends Outer ,其构造函数链,即使未显式调用
      • 无论是隐式的还是显式的,构造函数都将层次结构链接起来。

    但是为什么编译器要求 外甥女 构造函数接受 Outer o O() 是否被调用?

    现在,这是特定于内部类语义的:这样做是为了确保 外甥女 有一个封闭的 Outer 实例为 外部内部 超一流的 外甥女 . 否则, 外部内部 将没有的封闭实例 调用 outerMethod() 在。

        4
  •  2
  •   Luke Maurer    15 年前

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

    这就是为什么我们有有趣的语法 instance.new Inner() instance.super() _ 谁的 Inner ?_不是很明显。(在外部类的非静态方法中,您可以这样说 new Inner() 和往常一样,这是 this.new Inner() )

        5
  •  0
  •   Phani    15 年前

    永远不要忘记基本原则,在调用子类构造函数的过程中,总是先实例化父类,而不考虑内部/外部类。在您的场景中,当您扩展内部类并且内部类是父类的成员时,需要先实例化父类,然后调用实际的内部类构造函数。