Eine Sich-Selbst-Implementierung

Der Zusammenhang zwischen inneren Klassen und äußeren Klassen und wie sie sich gegenseitig implementieren können.

Eine Klasse kann entweder von einer Klasse erben oder eine Schnittstelle erweitern. Es ergibt sich ein Sonderfall, wenn wir eine Schnittstelle implementieren, die innerhalb der eigenen Klasse liegt, die die Schnittstelle deklariert. Das sieht etwa so aus:

class Outer implements Outer.InterfaceInner
{
  interface InterfaceInner
  {
  void knexDirDeineWelt();
  }

  public void knexDirDeineWelt()
  {
  }
}

Prinzipiell spricht erst einmal nichts gegen diese Implementierung. Innere Klassen, wie InterfaceInner eine ist, werden auf eine extra Klassendateien abgebildet, da es innerer Klassen beziehungsweise Schnittstellen sowieso nicht für die Laufzeitumgebung gibt. In unserem Fall könnte der Compiler die Datei Outer$InterfaceInner erzeugen. Im nächsten Schritt würde dann Outerdiese Schnittstelle erweitern und wie im Beispiel eine Methode überschreiben.

So schön dies auch aussieht: Es funktioniert nicht. Frühe Compiler erlaubten diese Schreibeweise, aber sie führt zu zirkulären Abhängigkeiten.

cyclic inheritance involving Outer

Wenn InterfaceInner zuerst übersetzt würde und dann Outer, wäre es noch zu verstehen, doch das Problem machen zum Beispiel Deklarationen in der inneren Klasse, die abhängig sind von der Äußeren. Wir könnten etwa den Rückgabewert von knexDirDeineWelt() ändern, dass es ein Outer Objekt zurückliefert.

class Outer implements Outer.InterfaceInner
{
  interface InterfaceInner
  {
    Outer knexDirDeineWelt();
  }

  public void knexDirDeineWelt()
  {
  }
}

Jetzt sehen wir: Ohne InterfaceInner kein Outer, da dies knexDirDeineWelt() vorschreibt und ohne Outer kein InterfaceInner, da sonst der Rückgabewert nicht bekannt ist. Mitunter wäre das Problem noch lösbar, aber hier lässt der Compiler lieber die Finger von.

Innere Klasse vor der äußeren

Dass es nicht unmöglich ist, eine innere Klasse von der äußeren Abzuleiten zeigt folgendes Beispiel:

interface I
{
  void boo();
  interface J extends I
  {
  }

  J foo();
}

Es ist problemlos möglich, dass die innere Schnittstelle die äußere erweitert. Im Gegensatz zum vorherigen Beispiel ist in diesem Fall die Problematik genau umgekehrt. Es ist auch möglich, dass eine innere Klasse eine äußere erweitert.

class O
{
  class I extends O
  {
    void bar()
    {
    }
  }

  void bar() { }
}

Über Christian Ullenboom

Ich bin Christian Ullenboom und Autor der Bücher ›Java ist auch eine Insel. Einführung, Ausbildung, Praxis‹ und ›Java SE 8 Standard-Bibliothek. Das Handbuch für Java-Entwickler‹. Seit 1997 berate ich Unternehmen im Einsatz von Java. Sun ernannte mich 2005 zum ›Java-Champion‹.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.