Das Schlüsselwort Java super. Wie du auf Methoden und Konstruktoren einer Oberklasse zugreifst.

Keylearnings:

  • Wie du mit Hilfe des Schlüsselworts super den Java Konstruktor einer Oberklasse aufrufst.
  • Die Bedeutung des Schlüsselworts java super
  • Wie du mit Hilfe von Java super eine Methode der Oberklasse aufrufst.
  • Wie du mit Hilfe des Schlüsselwortes super Namenskonflikte innerhalb einer Vererbungshierarchie vermeidest.
  • Der Unterschied zwischen den Schlüsselwörtern this und super.
  • Wann wird ein Java Konstruktor aufgerufen?

Kopfkratzen!

Das Schlüsselwort Java super wirkte wie Juckpulver auf meinem Kopf.

Ähnlich wie das Schlüsselwort Java this, löste es die totale Verwirrung aus!

Aber dir muss es nicht genauso gehen.

In diesem Artikel erkläre ich dir was es mit dem Java super Schlüsselwort auf sich hat.

Wir verwenden das Schlüsselwort super in drei Szenarien.

  1. Um den Java Konstruktor einer Oberklasse zu verwenden!
  2. Um die Methode einer Oberklasse aufzurufen!
  3. Um Namenskonflikte in einer Vererbungshierarchie aufzulösen!

Fällt dir was auf?

In allen Szenarien haben wir es mit einer Vererbungshierarchie zu tun.

Um das Schlüsselwort super zu verstehen, ist es also zwingend erforderlich, dass du weißt wie Vererbung in Java funktioniert.

Beginnen wir mit dem Aufruf einer Methode in einer Oberklasse.

Java super zum Aufruf des Konstruktors einer Oberklasse

Lass uns praktisch werden und ein Beispiel betrachten. Wenn du meinen Blog schon länger liest, dann wird dir das Vierbeiner-Beispiel bekannt vorkommen.

1: public abstract class Vierbeiner {
	
2:	protected String name = null;
	
3:	Vierbeiner(String name){
4:		this.name = name;
5:	}	
6: }

Die Klasse enthält ein geschütztes Attribut name, auf das wir aus der Vierbeiner-Unterklasse zugriff haben. Außerdem enthält die Klasse einen Konstruktor, mit dem wir das Attribut name initialisieren.

Da es sich bei dieser Klasse um eine abstrakte Klasse handelt, können wir keine Vierbeiner-Instanzen erzeugen und die Klasse kann nur als Ableitung eines konkreten Vierbeiners verwendet werden.

Und was ist unser Lieblings-Vierbeiner? Natürlich ein Hund! Dieser hier!

java super Schlüsselwort

Mit Hilfe des Schlüsselwortes extends leiten wir also einen Hund von der Klasse Vierbeiner ab.

public class Hund extends Vierbeiner{
		
}

Auch wenn die Klasse Hund noch keinerlei Funktionalität aufweist, sollte es doch möglich sein eine Hunde-Instanz zu erzeugen. Oder?

Starten wir einen Versuch!

Hund hund = new Hund();

Ojee, wenn wir das Programm starten erhalten wir eine Fehlermeldung.

Implicit super constructor Vierbeiner() is undefined for default constructor.

Woran liegt’s?

Die Laufzeitumgebung versucht den Standard-Konstruktor Vierbeiner() der Klasse Vierbeiner aufzurufen, und da dieser nicht definiert ist, wird eine entsprechende Fehlermeldung geworfen.

Aber warum geht die Laufzeitumgebung überhaupt auf die Suche nach dem Konstruktor Vierbeiner?

Dröseln wir das mal im einzelnen auf.

Wann wird ein Java Konstruktor aufgerufen?

Obwohl unsere Klasse Hund keinen Konstruktor besitzt, wird während der Erzeugung des Hunde-Objekts, durch die Anweisung new Hund() der Standardkonstruktor Hund() aufgerufen.

Ist in einer Klasse nämlich kein Konstruktor definiert, dann (und nur dann) führt der Compiler automatisch einen Standard-Konstruktor ohne Inhalt aus.

Um die Aufrufe der Konstruktoren besser verfolgen zu können, erstellen wir allerdings einen eigenen Standard-Konstruktor, im dem wir eine Bildschirmausgabe ausgeben.

public class Hund extends Vierbeiner{
     public Hund(){
         System.out.println("Standard-Konstruktor Hund!");
     }
}

Welche Auswirkung hat das Schlüsselwort extends bei der Abarbeitung des Konstruktors?

Da wir den Hund von der Klasse Vierbeiner ableiten, sucht der Compiler auch hier nach dem Standard-Konstruktor Vierbeiner. Weil diese Klasse bereits einen Konstruktor Vierbeiner(String Name) besitzt, wird kein Konstruktor automatisch erzeugt, weshalb es zu einem Laufzeitfehler kommt.

Um das Programm wenigstens ohne Fehler starten zu können, ergänzen wir die Klasse Vierbeiner um den Standard-Konstruktor (Zeile Drei) im folgenden Code!

1: public abstract class Vierbeiner {
	
2:	protected String name = null;
	
3:	public Vierbeiner(){
4:            System.out.println("Standard-Konstruktor Vierbeiner!");
5:      }
	
6:	Vierbeiner(String name){
7:		this.name = name;
8:      }

Zur besseren Nachvollziehbarkeit der Aufrufe geben wir auch hier, im Standard-Konstruktor, eine Bildschirmmeldung aus.

Beim Erzeugen einer Hunde-Instanz wird zunächst der Standard-Konstruktor des Hundes aufgerufen. Bevor dieser abgearbeitet wird, findet ein Aufruf des Standard-Konstruktor der Vierbeiner-Klasse statt.

Daher liefert die Erstellung eines Hunde-Objekts

Hund hund = new Hund();

folgende Ausgabe:

Standard-Konstruktor Vierbeiner!
Standard-Konstruktor Hund!

Es wird also zuerst der Konstruktor aus der Klasse Vierbeiner aufgerufen.

Aber mal ehrlich! Das ist einfach nur doof! 🙂

Wir haben jetzt zwar eine Hunde-Instanz. Aber eine ziemlich leere. Das einzige Attribut in unserer Klassen-Hierarchie name hat immer den Wert null.

Es wäre doch viel schöner, wenn wir nicht den Standard-Konstruktor sondern den Konstruktor Vierbeiner(String name) aufrufen würden um das Attribut name zu initialisieren.

Und hier hat das Java super Schlüsselwort seinen großen Auftritt. Mit Java super können wir nämlich die Konstruktoren der Oberklasse aufrufen.

Das Schlüsselwort super wird wie eine Methode verwendet.

Okay, lass uns den Konstruktor Vierbeiner(String name) aufrufen.

Hierfür müssen wir den Standard-Konstruktor wie folgt anpassen:

1: public Hund(){
2:	super("Bello");
3:	System.out.println("Standard-Konstruktor Hund!");
4:}

In der zweiten Zeile rufen wir Java super mit dem Parameter „Bello“ auf. Das führt dazu, dass der Compiler in der Oberklasse nach einem Java Konstruktor mit EINEM String Parameter in der Parameterliste sucht und diesen ausführt.

Genau wie beim überschreiben einer Methode, wird auch beim Schlüsselwort super die Parameterliste verwendet um den richtigen Konstruktor aufzurufen.

Bei unserem Beispiel führt das zu einer Ausführung des Java Konstruktors Vierbeiner(String name), der das Attribut name initialisiert.

Wichtig ist auch hier, dass zuerst der Konstruktor aus der Oberklasse abgearbeitet wird. Aus diesem Grund muss das Schlüsselwort super die erste Anweisung im Java Konstruktor Hund() sein.

Naja, so richtig toll ist das noch immer nicht. Schließlich wollen wir auch Hunde erzeugen, die nicht Bello heißen.

Hierfür fügen wir der Klasse Hund einen weiteren Java Konstruktor hinzu, dem wir den Namen des zu erzeugenden Hundes als Parameter mitgeben können.

Allerdings befindet sich das Attribut name nicht in der Klasse Hund sondern in der Oberklasse Vierbeiner und wird mit dem Konstruktor dieser Klasse initialisiert.

Du ahnst es sicher schon womit wir dieses Problem lösen. Genau! Mit Java super schleusen wir den String Parameter, der den Namen des Hundes enthält, bis in die Oberklasse durch.

1: public class Hund extends Vierbeiner{
	
2:   public Hund(){
3:	super("Bello");
4:	System.out.println("Standard-Konstruktor Hund!");
5:    }
	
6:   Hund(String name){
7:    	super(name);
8:    }
9:}

Jetzt können wir beim Erzeugen eines Hunde-Objektes dem Java Konstruktor den Namen des Hundes als Parameter übergeben.

Hund hund = new Hund("Hugo");

Die Anweisung new Hund("Hugo") ruft den Konstruktor Hund(String name) aus der Klasse Hund auf. Das erste was hier gemacht wird, ist über das Schlüsselwort super den Java Konstruktor Vierbeiner(String name) mit dem Argument „Hugo“ aufzurufen (Zeile 7), womit das Vierbeiner Attribut name mit dem String Hugo initialisiert wird.

Auf diese Weise haben wir ein Hunde-Objekt mit dem Namen Hugo erzeugt.

Wichtig hierbei ist, dass die Instanziierung eines Objektes von oben nach unten erfolgt. In unserem Fall wird also zuerst der Konstruktor aus der Klasse Vierbeiner abgearbeitet und erst dann der Konstruktor aus der Klasse Hund ausgeführt.

Das hat zur Folge, dass das Schlüsselwort super immer die erste Anweisung innerhalb eines Java Konstruktor sein muss.

Soviel zu dem Aufruf eines Konstruktors einer Oberklasse. Wenden wir uns dem nächsten Einsatzgebiet von  Java super zu. Nämlich dem Aufruf von Methoden einer Oberklasse.

java super

Java super zum Aufruf einer Methode in einer Oberklasse

Wir haben uns hier bereits über das Überschreiben von Methoden einer Oberklasse unterhalten.

Beim Überschreiben einer Methode lösen wir die Methode der Oberklasse vollständig durch die (gleichnamige) Methode einer Unterklasse ab.

Ziel einer Vererbungshierarchie ist meist jedoch nicht die Ersetzung einer Funktionalität sondern vielmehr die Verfeinerung.

In diesem Fall sprechen wir manchmal auch von einer Verkettung.

Noch nicht klar? Okay, nicht schlimm. Schauen wir uns das ganze anhand eines Beispiels an.

Vierbeiner sind hungrig und müssen fressen. Daher ist es ein guter Plan unsere Vierbeiner Klasse um eine fressen Methode zu erweitern.

public void fressen(){
	System.out.println("Ich habe hunger!");
}

Diese Methode macht nichts weiter als eine Bildschirmausgabe zu erzeugen!

Worin unterscheidet sich die fressen() Methode eines allgemeinen Vierbeiners von der eines Hundes?

Genau! Ein Hund bittet zusätzlich zivilisiert um einen Fressnapf!

Wie können wir unsere Klasse Hund um diese Funktionalität erweitern?

Zunächst die Art, auf die du es nicht machen solltest!

Wir kopieren die fressen() Methode aus der Klasse Vierbeiner in die Klasse Hund und ergänzen diese Methode um eine entsprechende Bildschirmausgabe. Also:

public void fressen(){
    	System.out.println("Ich habe hunger!");
        System.out.println("Bitte bring mir einen Napf!");
}

Das entspricht dem klassischen Überschreiben einer Methode.

Auch wenn es in unserem Minibeispiel kaum auffällt, hat diese Vorgehensweise einen großen Nachteil, den wir in der objektorientierten Programmierung vermeiden wollen.

Durch das Kopieren der Methode erzeugst du doppelten Programmcode!

Viel besser wäre es doch, wenn wir die Funktionalität der fressen() Methode in der Oberklasse Vierbeiner vollständig verwenden könnten und lediglich um das zusätzliche Verhalten eines Hundes ergänzen würden.

Und genau das können wir mit Hilfe von Java super erreichen! Mit der Hilfe des Schlüsselwortes super können wir nämlich aus der fressen() Methode des Hundes die fressen() Methode des Vierbeiners aufrufen.

Im folgenden die fressen() Methode der Klasse Hund unter Verwendung von Java super.

1: public void fressen(){
2:    super.fressen();
3:    System.out.println("Bitte bring mir einen Napf!");
4:}

In Zeile zwei rufen wir mit Hilfe von super die fressen() Methode der Oberklasse Vierbeiner auf, welche die Bildschirmausgabe

Ich habe hunger!

erzeugt.

Nachdem die fressen() Methode in der Klasse Vierbeiner abgearbeitet ist, wird die Verarbeitung in der gleichnamigen Methode der Klasse Hund in Zeile Drei fortgesetzt, was zur Bildschirmausgabe

Bitte bring mir einen Napf!

führt!

Genau wie beim Aufruf eines Java Konstruktor einer Oberklasse, werden auch hier die Methoden innerhalb der Vererbungshierarchie von oben nach unten abgearbeitet.

In unserem Beispiel wird also zuerst die fressen() Methode der Vierbeiner-Klasse ausgeführt und erst danach die entsprechende Methode aus der Klasse Hund.

Das hat zur Folge, dass auch hier das Schlüsselwort super die erste Anweisung innerhalb einer Methode sein muss.

Noch eine Warnung. Nicht zu Hause nach machen

Man könnte auf die Idee kommen die Methoden der Oberklasse über deren Namen aufzurufen. In unserem fressen() Beispiel würde das folgendermaßen aussehen.

1: public void fressen(){
2:    fressen();
3:    System.out.println("Bitte bring mir einen Napf!");
4:}

Das hat aber katastrophale folgen, da sich in Zeile Zwei die Methode unendlich oft selber aufruft. Der Methodenaufruf in Zeile Zwei wird so interpretiert als stünde das Schlüsselwort this vor dem Methodenaufruf.

Der Compiler interpretiert die zweite Zeile also als this.fressen().

Soviel zu dem Aufruf von Methoden einer Oberklasse. Zu guter letzt wollen wir der Vollständigkeit wegen noch ein weiteres Einsatzgebiet von Java super besprechen.

Java super zum Auflösen von Namenskonflikten in einer Vererbungshierarchie

Genau wie wir Methoden einer Oberklasse mit Hilfe von super aufrufen können, kann Java super auch zum Zugriff auf die Attribute einer Oberklasse verwendet werden.

Da wir allerdings gelernt haben, dass wir auf Attribute einer Klasse mit Hilfe von getter- und setter- Methoden  zugreifen sollten, werden wir das in der Realität eher selten machen.

Dennoch wollen wir uns ein kleines Beispiel ansehen, das uns außerdem noch einmal den Unterschied zwischen den Schlüsselwörtern Java this und super vor Augen führt.

1: class A{
	
2:	public int x = 10;
	
3:}

4: class B extends A{
	
5:	public int x = 100;	
		
6:}

Das Beispiel besteht aus zwei Klassen A und B wobei B eine Unterklasse von A ist. Beide Klassen enthalten das gleichnamige Integer-Attribut x.

Unser Ziel ist es die Klasse B um eine Methode printAttributes zu ergänzen, die das Attribut x beider Klassen auf dem Bildschirm ausgibt.

Aber wie lösen wir den Namenskonflikt auf?

Genauer wie legen wir fest, ob wir das Attribut x aus der Klasse A oder B meinen?

Diesen Job übernehmen für uns die Schlüsselwörter Java this und super.

Wir ergänzen die Klasse B um eine Methode printAttributes.

1: public void printAttributes(){
2:	System.out.println(this.x);
3:	System.out.println(super.x);
4:}

Welche Bildschirmausgabe erwartest du, wenn wir diese Methode aufrufen?

In der zweiten Zeile geben wir das Attribut x mit vorangestelltem this aus, da wir die Methode printAttributes in der Klasse B definiert haben, bezieht sich das Schlüsselwort this auf diese Klasse und es wird das Attribut x aus der Klasse B ausgegeben.

Da wir in Zeile Drei das Schlüsselwort super dem Attribut x voranstellen beziehen wir uns hier auf die Oberklasse A.

Somit liefert die Methode printAttributes folgende Bildschirmausgabe:

100
10

Fazit: In diesem Artikel hast du die Anwendungen des Java Schlüsselwortes super kennengelernt. Mit Hilfe dieses Schlüsselworts kannst du zum einen den Java Konstruktor einer Oberklasse aufrufen und zum anderen eine Methode einer Oberklasse verfeinern. Außerdem kannst du mit Hilfe dieses Schlüsselwortes Namenskonflikte innerhalb einer Vererbungshierarchie vermeiden.

Ich freue mich auf deine Fragen im Kommentarbereich!

Hat dir der Artikel gefallen? Dann folge uns doch am besten gleich auf Facebook!

Hallo ich bin Kim und ich möchte ein großer Programmierer werden. Machst du mit?

Kommentare (4)

  • Antworte

    Klasse Erklärung. Auch wenn ich Hunde hasse, hat das Beispiel mit den Vierbeinern einiges klar gemacht.

    Weiter so!

    • Hi Khalid, danke für dein Feedback! Ein anderes Beispiel, an dem du das ganze veranschaulichen kannst ist das Beispiel Fahrzeug. Von einem Fahrzeug könntest du Beispiel ein Auto ein LKW, oder ein Moped ableiten und in diesen Klassen mit Hilfe des Schlüsselworts super Methoden und Konstruktoren der Fahrzeug Oberklasse aufrufen. Viele Grüße Kim

  • Antworte

    Hat mir sehr weitergeholfen ! Vielen Dank ,bitte weiter so 🙂

    • Hallo Arthur, vielen Dank für dein Feedback. Freue mich wenn ich weiterhelfen kann. Viele Grüße Kim

Hinterlasse ein Kommentar