1. Verwendung von super zum Aufruf von Methoden der Basisklasse
Wenn Sie eine Unterklasse erstellen, kommt es manchmal vor, dass Sie auf Felder oder Methoden der Basisklasse zugreifen müssen – besonders, wenn Sie sie überschrieben oder „überschattet“ (versteckt) haben. Dafür gibt es in Java das spezielle Schlüsselwort super.
Als Analogie: super ist wie „Mama, hilf mir!“, wenn Sie in der Unterklasse ausdrücklich auf etwas zugreifen wollen, das in der Elternklasse definiert ist.
Stellen Sie sich vor, es gibt eine Klasse Animal mit der Methode eat(), die einfach "Das Tier frisst" ausgibt. Und in der Klasse Cat möchten Sie, dass die Katze erst etwas Eigenes tut (z. B. miaut) und danach trotzdem das Standard‑„Tier frisst“ ausführt. Genau hier hilft super.eat().
Wenn Sie in der Unterklasse eine Methode überschreiben, aber innerhalb dieser Methode dennoch die Implementierung aus der Basisklasse aufrufen möchten, verwenden Sie super.methodName().
Beispiel: Verhalten erweitern
class Animal {
void eat() {
System.out.println("Das Tier frisst");
}
}
class Cat extends Animal {
@Override
void eat() {
System.out.println("Die Katze schnuppert am Futter...");
super.eat(); // ruft die Methode eat() aus Animal auf
System.out.println("Die Katze schnurrt zufrieden");
}
}
Wie funktioniert das?
- Wenn eat() auf einem Objekt vom Typ Cat aufgerufen wird, wird zunächst der Code aus Cat.eat() ausgeführt, also die eigene Methode.
- Innerhalb dieser Methode rufen wir explizit super.eat() auf, also die Implementierung aus der Elternklasse Animal.
- So lässt sich zusätzliches Verhalten hinzufügen, ohne das „Elternverhalten“ zu vergessen.
Praxis: Einsatz in einer Anwendung
Angenommen, in unserer Lernanwendung gibt es die Basisklasse Animal und die Unterklassen Dog und Cat. Wir möchten, dass beim Füttern sowohl allgemeine Aktionen (z. B. Erhöhung der Sättigung) als auch spezifsche für jedes Tier ausgeführt werden.
class Animal {
int satiety = 0;
void eat() {
satiety += 10;
System.out.println("Das Tier frisst. Sättigung: " + satiety);
}
}
class Dog extends Animal {
@Override
void eat() {
System.out.println("Der Hund wedelt vor dem Fressen mit dem Schwanz");
super.eat();
}
}
Rufen Sie jetzt dog.eat() auf, sehen Sie beide Meldungen, und satiety erhöht sich korrekt.
2. Verwendung von super für den Zugriff auf Felder der Basisklasse
Wenn Sie in der Unterklasse ein Feld mit demselben Namen wie in der Elternklasse deklarieren, „überschattet“ es das Elternfeld. Manchmal müssen Sie auf das ursprüngliche Feld der Basisklasse zugreifen – dafür verwenden Sie super.fieldName.
Beispiel: Überschatten eines Feldes
class Animal {
String name = "Tier";
}
class Cat extends Animal {
String name = "Katze";
void printNames() {
System.out.println("Name aus Cat: " + name);
System.out.println("Name aus Animal: " + super.name);
}
}
Der Aufruf new Cat().printNames(); gibt aus:
Name aus Cat: Katze
Name aus Animal: Tier
In der Praxis wird das Überschatten von Feldern ohne zwingenden Grund nicht empfohlen, aber es ist gut, diese Möglichkeit zu kennen.
3. Aufruf des Konstruktors der Basisklasse über super(...)
Wie werden Objekte in einer Hierarchie erstellt?
Wenn Sie ein Objekt einer Unterklasse erstellen, wird zuerst der Konstruktor der Basisklasse aufgerufen und erst danach der Konstruktor der Unterklasse. Das ist nötig, damit alle Felder korrekt initialisiert werden, denn die Unterklasse „erbt“ einen Teil des Zustands von der Elternklasse.
Expliziter Aufruf des Konstruktors der Basisklasse
Wenn die Basisklasse einen parameterlosen Konstruktor hat, ist alles einfach: Java ruft ihn automatisch vor dem Konstruktor der Unterklasse auf. Hat die Elternklasse jedoch keinen parameterlosen Konstruktor, müssen Sie den passenden Konstruktor explizit über super(...) aufrufen.
Beispiel:
class Animal {
String name;
Animal(String name) {
this.name = name;
System.out.println("Tier erzeugt: " + name);
}
}
class Cat extends Animal {
Cat(String name) {
super(name); // unbedingt! Es gibt keinen parameterlosen Animal()-Konstruktor
System.out.println("Katze erzeugt: " + name);
}
}
Der Aufruf new Cat("Murka") schreibt:
Tier erzeugt: Murka
Katze erzeugt: Murka
Wichtig: Der Aufruf des Elternkonstruktors über super(...) muss die erste Zeile des Unterklassenkonstruktors sein. Wenn Sie davor etwas schreiben, wird der Compiler reklamieren und Sie daran erinnern.
Nicht explizit aufgerufen?
Wenn die Elternklasse nur Konstruktoren mit Parametern hat und Sie diese nicht ausdrücklich über super(...) aufrufen, meldet der Compiler einen Fehler: "constructor Animal in class Animal cannot be applied to given types".
4. Nützliche Feinheiten
Wann verwendet man super?
Zum Erweitern statt zum Ersetzen des Verhaltens.
Manchmal möchten Sie das Verhalten einer Methode nicht vollständig ersetzen, sondern nur „erweitern“. Zum Beispiel etwas vor oder nach der Logik der Elternklasse hinzufügen. In solchen Fällen verwenden Sie super.methodName() im Körper der überschriebenen Methode.
Zur Initialisierung geerbter Felder.
Wenn die Elternklasse Felder hat, die zwingend initialisiert werden müssen (z. B. der Name eines Tiers), rufen Sie den passenden Elternkonstruktor mit den erforderlichen Parametern über super(...) auf.
Für den Zugriff auf verdeckte Felder/Methoden.
Wenn Sie aus irgendeinem Grund ein Feld oder eine Methode der Elternklasse überschattet haben und dennoch darauf zugreifen müssen, verwenden Sie super.fieldName oder super.methodName().
Einschränkungen und Besonderheiten der Verwendung von super
- Den Aufruf des Elternkonstruktors über super(...) darf man nur im Konstruktor und nur als erste Zeile vornehmen.
- Außerhalb des Unterklassenkonstruktors kann der Elternkonstruktor nicht aufgerufen werden.
- Wenn super(...) nicht explizit aufgerufen wird, versucht Java den parameterlosen Elternkonstruktor aufzurufen (falls vorhanden).
- Das Schlüsselwort super darf in statischen Methoden nicht verwendet werden – nur in Instanzmethoden und in Konstruktoren.
- Wenn eine Methode oder ein Feld der Elternklasse private ist, hilft super nicht: Auf private Member gibt es keinen Zugriff.
5. Beispiele zur Festigung
Beispiel 1. Methode mit super erweitern
class Animal {
void makeSound() {
System.out.println("Das Tier macht ein Geräusch");
}
}
class Dog extends Animal {
@Override
void makeSound() {
super.makeSound(); // zuerst die Standardaktion ausführen
System.out.println("Der Hund bellt: Wau-wau!");
}
}
Beispiel 2. Aufruf des Konstruktors der Basisklasse
class Vehicle {
String brand;
Vehicle(String brand) {
this.brand = brand;
System.out.println("Fahrzeug: " + brand);
}
}
class Car extends Vehicle {
int year;
Car(String brand, int year) {
super(brand); // ruft den Elternkonstruktor auf
this.year = year;
System.out.println("Auto " + brand + ", Jahr: " + year);
}
}
Car car = new Car("Toyota", 2023);
// Ausgabe:
// Fahrzeug: Toyota
// Auto Toyota, Jahr: 2023
Beispiel 3. Klassischer Fehler: super(...) vergessen
class Animal {
String name;
Animal(String name) {
this.name = name;
}
}
class Cat extends Animal {
Cat() {
// super(); // Fehler! Es gibt keinen parameterlosen Animal()-Konstruktor
// super(name) muss explizit aufgerufen werden
super("Namenlose Katze");
}
}
6. Häufige Fehler bei der Arbeit mit super
Fehler Nr. 1: Aufruf von super(...) nicht in der ersten Zeile des Konstruktors.
Java verlangt strikt, dass der Aufruf des Elternkonstruktors über super(...) die erste Zeile des Unterklassenkonstruktors ist. Wenn Sie davor etwas tun (z. B. eine Meldung ausgeben), meldet der Compiler einen Fehler.
Fehler Nr. 2: Kein passender Konstruktor in der Elternklasse.
Wenn die Basisklasse keinen parameterlosen Konstruktor hat und Sie keinen anderen Konstruktor über super(...) aufrufen, kann der Compiler keinen Standardaufruf erzeugen und meldet einen Fehler.
Fehler Nr. 3: Versuch, über super auf private Member der Elternklasse zuzugreifen.
Das Schlüsselwort super gewährt keinen magischen Zugriff auf private Felder oder Methoden der Elternklasse. Was als private deklariert ist, bleibt für die Unterklasse unzugänglich.
Fehler Nr. 4: Überschatten von Feldern und Methoden ohne Verständnis.
Wenn Sie in der Unterklasse ein Feld oder eine Methode mit demselben Namen wie in der Elternklasse deklarieren und das vergessen, kann es zu unerwarteten Ergebnissen kommen. Denken Sie daran: In diesem Fall ist der Zugriff auf das Eltern‑Member nur über super möglich.
Fehler Nr. 5: Verwendung von super in einer statischen Methode.
In statischen Methoden darf super nicht verwendet werden, weil sie nicht zu einem konkreten Objekt gehören.
GO TO FULL VERSION