4.5.2 | Verketten von Konstruktoren |
Der Konstruktor von Square, den wir im vorangegangenen Schritt definiert haben, weist eine Besonderheit auf. Die Koordinaten und die Farbe werden nicht mitthis.x = x; this.y = y; this.color = color;zugewiesen (was ohne weiteres möglich wäre). Stattdessen wird der Konstruktor von Point mitsuper(x, y, color);aufgerufen. In dieser Syntax dient das Schlüsselwort super stets dazu, einen Konstruktor der Oberklasse aufzurufen. Dadurch können Initialisierungsvorgänge, die bei der Unterklasse identisch sind, einfach übernommen werden, ohne sie nochmals zu implementieren. Die Unterklasse ruft stattdessen einfach einen geeigneten Konstruktor der Oberklasse auf und implementiert selbst nur die zusätzliche Funktionalität, die im Rahmen der Erweiterung nötig ist. Im Beispiel von Point und Square ist das Setzen der Koordinaten und der Farbe für Punkte und Quadrate identisch. Für Quadrate muss nur noch zusätzlich die Seitenlänge eingestellt werden.
Falls man einen geerbten Konstruktor wiederverwenden will, ist zu beachten, dass dessen Aufruf grundsätzlich an erster Stelle des neuen Konstruktors stehen muss.
Das Erzeugen eines neuen Exemplars einer Klasse läuft in folgenden Schritten ab:Dieser Ablauf sei an folgendem Beispiel verdeutlicht:
- Zuerst wird ein Speicherbereich belegt, der das neue Exemplar aufnimmt. Bei diesem Schritt werden auch die Datenelemente mit den Initialwerten der jeweiligen Datentypen belegt.
- Als nächstes werden die Konstruktoren aller Oberklassen entlang der Vererbungshierarchie nach oben ausgeführt. Falls ein Konstruktor hierbei nicht explizit einen Konstruktor der Oberklasse mit super aufruft, wird der parameterlose Konstruktor der Oberklasse verwendet.
- Anschließend werden die Datenelemente, die in der Deklaration eine Zuweisung enthalten, mit den entsprechenden Werten belegt.
- Dann werden die Exemplar-Initialisierungsteile in der Reihenfolge ihrer Deklaration ausgeführt, sofern es welche gibt.
- Als Letztes wird der Code des aufgerufenen Konstruktors ausgeführt.
class A { public A() { System.out.println("A"); } } class B extends A { int x = 1; { System.out.println("1. Exemplar-Initialisierung: "+x); } public B() { System.out.println("B: "+x); } { System.out.println("2. Exemplar-Initialisierung: "+x); } }Die Anweisung new B() liefert die Ausgabe:A 1. Exemplar-Initialisierung: 1 2. Exemplar-Initialisierung: 1 B: 1Besonders zu beachten ist, dass der Konstruktor von A gemäß der ersten Regel zur Ausführung kommt, obwohl er nicht ausdrücklich in B() aufgerufen wird.