Wenn Java in Version 1.1 der Sprache innere Klassen hinzugefügt wurden, wurden sie ursprünglich als Umwandlung in 1.0-kompatiblen Code definiert. Wenn Sie sich ein Beispiel für diese Transformation ansehen, wird es meiner Meinung nach viel klarer machen, wie eine innere Klasse tatsächlich funktioniert.
Betrachten Sie den Code aus Ian Roberts 'Antwort:
public class Foo {
int val;
public Foo(int v) { val = v; }
class Bar {
public void printVal() {
System.out.println(val);
}
}
public Bar createBar() {
return new Bar();
}
}
Bei der Transformation in 1.0-kompatiblen Code Barwürde diese innere Klasse ungefähr so aussehen:
class Foo$Bar {
private Foo this$0;
Foo$Bar(Foo outerThis) {
this.this$0 = outerThis;
}
public void printVal() {
System.out.println(this$0.val);
}
}
Dem inneren Klassennamen wird der äußere Klassenname vorangestellt, um ihn eindeutig zu machen. Ein verstecktes privates this$0Mitglied wird hinzugefügt, das eine Kopie des äußeren enthält this. Und ein versteckter Konstruktor wird erstellt, um dieses Mitglied zu initialisieren.
Und wenn Sie sich die createBarMethode ansehen , würde sie sich in etwa so verwandeln:
public Foo$Bar createBar() {
return new Foo$Bar(this);
}
Mal sehen, was passiert, wenn Sie den folgenden Code ausführen.
Foo f = new Foo(5);
Foo.Bar b = f.createBar();
b.printVal();
Zuerst instanziieren wir eine Instanz von Foound initialisieren das valMitglied auf 5 (dh f.val = 5).
Als nächstes rufen wir auf f.createBar(), das eine Instanz von instanziiert Foo$Barund das this$0Mitglied auf den Wert von thisübergeben von createBar(dh b.this$0 = f) initialisiert .
Schließlich rufen wir auf, b.printVal()welche Versuche zu drucken b.this$0.valsind, f.valwelche 5 sind.
Das war eine regelmäßige Instanziierung einer inneren Klasse. Schauen wir uns an, was passiert, wenn Barvon außen instanziiert wird Foo.
Foo f = new Foo(5);
Foo.Bar b = f.new Bar();
b.printVal();
Wenn Sie unsere 1.0-Transformation erneut anwenden, wird diese zweite Zeile ungefähr so aussehen:
Foo$Bar b = new Foo$Bar(f);
Dies ist fast identisch mit dem f.createBar()Anruf. Wieder instanziieren wir eine Instanz von Foo$Barund initialisieren das this$0Mitglied auf f. Also nochmal , b.this$0 = f.
Und wieder, wenn Sie anrufen b.printVal(), drucken Sie b.thi$0.val, f.valwas 5 ist.
Das Wichtigste ist, dass die innere Klasse ein verstecktes Mitglied hat, das eine Kopie thisder äußeren Klasse enthält. Wenn Sie eine innere Klasse innerhalb der äußeren Klasse instanziieren, wird sie implizit mit dem aktuellen Wert von initialisiert this. Wenn Sie die innere Klasse von außerhalb der äußeren Klasse instanziieren, geben Sie über das Präfix des newSchlüsselworts explizit an, welche Instanz der äußeren Klasse verwendet werden soll .