17

Javaの非静的なネストされたクラスに頭を悩ませるのに苦労しています。次の例を考えてみましょう。この例では、「Inner」、次に「Child」が出力されます。

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のインスタンスは常にOuterインスタンスに関連付ける必要があり、Innerを拡張するため、Childにも適用されることを理解しています。私の質問は、o.super()構文の意味です-なぜそれがInnerコンストラクターを呼び出すのですか?

super(args)スーパークラスコンストラクターsuper.method()を呼び出し、オーバーライドされたメソッドのスーパークラスバージョンを呼び出すために使用されるプレーンを見ただけですが、形式の何かを見たことはありませんinstance.super()

4

5 に答える 5

11

これは「修飾されたスーパークラスコンストラクター呼び出し」と呼ばれます。

ここから引用:

明示的なコンストラクター呼び出しステートメントは、次の2種類に分けることができます。

  • 代替コンストラクターの呼び出しは、キーワードthisで始まります(明示的な型引数が前に付いている可能性があります)。これらは、同じクラスの代替コンストラクターを呼び出すために使用されます。

  • スーパークラスコンストラクターの呼び出しは、キーワードsuper(明示的な型引数で始まる可能性があります)またはPrimary式のいずれかで始まります。これらは、直接スーパークラスのコンストラクターを呼び出すために使用されます。スーパークラスコンストラクターの呼び出しは、さらに細かく分割できます。

  • 修飾されていないスーパークラスコンストラクターの呼び出しは、キーワードsuperで始まります(明示的な型引数で始まる可能性があります)。

  • 修飾されたスーパークラスコンストラクターの呼び出しは、Primary式で始まります。これにより、サブクラスコンストラクターは、直接スーパークラス(§8.1.3)に関して、新しく作成されたオブジェクトのすぐに囲まれたインスタンスを明示的に指定できます。これは、スーパークラスが内部クラスである場合に必要になることがあります。

于 2010-05-14T02:32:49.350 に答える
11

内部クラス(非静的子クラス)は、基本的にネストされたクラス(静的子クラス)であり、親オブジェクトへの暗黙的なリンクがあります。静的なネストされたクラスを代わりに使用して記述された上記のコードは次のとおりです。

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()が何をしていたかを理解できるはずです。

于 2010-05-14T02:37:53.537 に答える
6

なぜo.super()inはコンストラクター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インスタンスがあることを確認するために行われます。それ以外の場合、のコンストラクターには、を呼び出すためのを囲むインスタンスがありません。Outer.InnerOuterInnerChildOuter.InnerOuterouterMethod()

于 2010-05-14T02:48:17.423 に答える
2

概念的には、非静的内部クラスは特定のオブジェクトに「属します」。これは、非静的フィールドまたはメソッドが特定のオブジェクトに属しているように、それぞれが独自のバージョンのクラスを取得するようなものです。

だから、私たちはとのような面白い構文を持っているのinstance.new Inner()ですinstance.super()—質問への答えが「しかし誰?」である文脈のため Inner。すぐにはわかりません。(外部クラスの非静的メソッドでは、new Inner()と言うことができます。いつものように、これはの略ですthis.new Inner()。)

于 2010-05-14T02:38:09.893 に答える
0

基本原則を常に忘れないでください。サブクラスコンストラクターを呼び出すプロセスでは、内部/外部クラスに関係なく、常に親クラスが最初にインスタンス化されます。シナリオでは、内部クラスを拡張していて、内部クラスが親クラスのメンバーであるため、インスタンス化してから実際の内部クラスコンストラクターを呼び出す必要があります。

于 2010-05-14T05:36:57.187 に答える