2010-05-14 9 views
15

Ich habe eine harte Zeit mit dem Kopf um nicht-statische verschachtelte Klassen in Java gewickelt. Betrachten Sie das folgende Beispiel, das "Inner" und dann "Child" ausgibt.Java: Nicht-statische geschachtelte Klassen und instance.super()

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

Ich verstehe, dass Instanzen der Inneren müssen immer mit einer äußeren Instanz zugeordnet werden, und dass das auch zu Kind gilt, da es sich Inner. Meine Frage ist, was die o.super() Syntax bedeutet - warum ruft es den Inner Konstruktor?

Ich habe nur ein einfaches super(args) verwendet, um rufen Sie den Oberklassenkonstruktors und super.method() nennt die Superclass-Version einer überschriebenen Methode, aber nie etwas von der Form instance.super() gesehen.

+0

LOL ... was hat das die "interview-questions" tag? – Cristian

+0

Im Rahmen eines Interviews für eine Java-Position wurde ich gebeten, ein IKM-Quiz zu absolvieren; Diese Frage ist eine vereinfachte Form des Quiz. – Kiv

+0

@Kiv hast du ein Beispiel für die Nutzung des realen Lebens? – chepseskaf

Antwort

9

Es heißt eine "qualifizierte Superklasse Konstruktor Aufruf".

Unter Berufung von here:

Explicit Konstruktor Aufruf-Anweisungen können in zwei Arten unterteilt werden:

  • Alternate Konstruktor Anrufungen beginnen mit dem Schlüsselwort dieser (möglicherweise mit expliziten Typargumente eingeleitet). Sie werden verwendet, um einen alternativen Konstruktor derselben Klasse aufzurufen.

  • Superklassenkonstruktoraufrufe beginnen entweder mit dem Schlüsselwort super (möglicherweise mit Argumenten mit explizitem Typ vorangestellt) oder mit einem Primary-Ausdruck. Sie werden verwendet, um einen Konstruktor der direkten Superklasse aufzurufen. Oberklassenkonstruktors Anrufungen werden weiter unterteilt:

  • Unqualifizierte Oberklassenkonstruktors Anrufungen mit dem Stichwort Super beginnen (möglicherweise mit expliziten Typargumente eingeleitet).

  • Qualifizierte Superklassenkonstruktoraufrufe beginnen mit einem Primary-Ausdruck. Sie ermöglichen einem Unterklassenkonstruktor, die unmittelbar umschließende Instanz des neu erstellten Objekts explizit in Bezug auf die direkte Oberklasse anzugeben (§8.1.3). Dies kann notwendig sein, wenn die Oberklasse eine innere Klasse ist.

9

innere Klassen (nicht-statische Kind-Klassen) sind im Wesentlichen Verschachtelte Klassen (statische Kind-Klassen) mit impliziten Verbindungen zurück Objekte zu ihren Eltern. Hier Ihr obiger Code ist, geschrieben stattdessen eine statische verschachtelte Klasse mit:

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

bei dieser Suche, sollten Sie in der Lage sein zu verstehen, was o.super() tat.

+2

In der Tat ist eine nicht-statische innere Klasse im Wesentlichen syntaktischen Zucker für die oben genannten, nach meinem Verständnis. –

+0

Nein, eine geschachtelte statische Klasse ist im Wesentlichen eine Klasse der äußeren Ebene, die nur zum Zweck des Packaging zur Verfügung steht. –

+1

Gut, richtig. Ich meine nur eine * nicht-statische * innere Klasse ist syntaktischer Zucker auf syntaktischem Zucker: -D –

2

Konzeptionell "gehört" eine nicht statische innere Klasse zu einem bestimmten Objekt. Es ist so, als ob jeder seine eigene Version der Klasse bekommt, ähnlich wie ein nicht-statisches Feld oder eine Methode zu einem bestimmten Objekt gehört.

Also das ist, warum wir lustige Syntax wie instance.new Inner() und instance.super() haben - für Kontexte, in denen die Antwort auf die Frage „aber derenInner?“ Nicht ohne weiteres ersichtlich ist. (In einer nicht-statischen Methode der äußeren Klasse, können Sie einfach new Inner() sagen, und wie üblich kurz das ist für this.new Inner().)

5

Warum o.super() in Child endet Aufruf Outer.Inner Konstruktor? Es ist einfach: weil Child extends Outer.Inner und Konstruktoraufrufe immer die Hierarchie verkettet sind.

Hier ist eine leichte Expansion auf Ihre Schnipsel zu veranschaulichen:

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

Diese Drucke:

Outer 
OuterInner 
OuterInnerChild 
ONE MILLION DOLLAR!!! 
Outer 
OuterChild 

Einige wichtige Beobachtungen:

  • Weil OuterInnerChild extends Outer.Inner, es erbt wealth, genau wie normale Unterklassensemantik
    • Und wie normale Unterklasse Semantik, der Konstruktor von OuterInnerChild Ketten an den Konstruktor Outer.Inner
  • Da OuterChild extends Outer, die Konstruktor Ketten, auch wenn sie nicht explizit implizit oder explizit
    • Ob aufgerufen, das Konstruktors Ketten up der Hierarchie

Aber warum die Compiler Forderung, dass OuterInnerChild Konstruktor ein Outer o nimmt, und dass o.super() aufgerufen wird?

Nun, das ist spezifisch für innere Klasse Semantik: es wird getan, um sicherzustellen, dass alle Instanzen von OuterInnerChild haben eine umschließende Outer Instanz für Outer.Inner, die Superklasse von OuterInnerChild. Andernfalls hätte der Konstruktor Outer.Inner keine umschließende Instanz Outer, um outerMethod() auf aufzurufen.

0

Immer die Grundprinzipien nicht vergessen: Beim Aufruf eines Unterklassenkonstruktors wird immer zuerst die Elternklasse unabhängig von inneren/äußeren Klassen instanziiert. In Ihrem Szenario, wenn Sie die innere Klasse erweitern und Ihre innere Klasse ein Mitglied der übergeordneten Klasse ist, die instanziiert werden muss, gefolgt von einem Aufruf des tatsächlichen inneren Klassenkonstruktors.