Vererbung und geschachtelte Klassen
Geschachtelte Klassen und Vererbung
Geschachtelte Klassen können von der umgebenden Klasse erben
public class A {
class B extends A { }
}
- Methoden und Attribute sind dann auf zwei Wegen sichtbar
- Als Member der äußeren Klassen
- Als geerbte Attribute und Methoden
- Die eigentlich getrennten Namensräume fallen zusammen
- Bei unqualifiziertem Zugriff haben die ererbten Attribute Vorrang vor den über die äußere Klasse sichtbaren
- Diese Konstruktion sollte vermieden werden, da sie sehr verwirrend und schwer zu lesen ist
Geschachtelte Klassen können beliebige Vererbungsbeziehungen eingehen, auch zur umgebenden Klasse. Von einer solchen Konstruktion ist aber dringend abzuraten, da ein kompliziertes Gemenge zwischen geerbten und über die Schachtelung sichtbaren Attributen entsteht, die nur schwer zu beherrschen ist. Neben der Sichtbarkeit stellt sich auch die Frage, wo die Attribute eigentlich liegen: im Objekt der umgebenden Klasse oder als ererbte Attribute im eigenen Objekt. Auch hier ist Chaos vorprogrammiert.
Beispiel: Innere Klassen und Vererbung
public class Outer {
protected String s;
private String t;
protected void methode() { System.out.println("Outer:methode()"); }
public class Inner extends Outer {
protected void methode() { System.out.println("Inner:methode()"); }
public void doIt() {
s = "geerbter String";
Outer.this.s = "String von aussen";
t = "nicht über Vererbung sichtbar";
Outer.this.methode();
methode();
}
}
}
Outer o = new Outer();
Outer.Inner i = o.new Inner();
i.doIt();
System.out.println(o.s);
System.out.println(i.s);
Outer:methode()
Inner:methode()
String von aussen
geerbter String
Quiz: Anonyme Innere Klassen
public class Twister {
private final String name;
Twister(String name) { this.name = name; }
private String name() { return name; }
private void reproduce() {
new Twister("reproduce") {
void printName() {
System.out.println(name());
}
}.printName();
}
public static void main(String[] args) {
new Twister("main").reproduce();
}
}
main
Auf den ersten Blick würde man erwarten, dass das Programm nicht kompiliert, da die innere Klasse auf eine private Methode von Twister
zugreift. Dies ist aber zulässig, weil innere Klassen Zugriff auf alle Methoden und Attribute der äußeren Klasse hat, unabhängig von der Sichtbarkeit. Private Methoden sind aber über die Vererbung nicht sichtbar (werden aber nicht vererbt). Deswegen greift der Aufruf name()
in der inneren Klasse nicht auf eine entsprechende, geerbte Methode der inneren Klasse zu, sondern einfach auf die trotz private
sichtbare Methode der äußeren Klasse.