Java Tutorial #28

Konstruktoren bei Vererbung

2019-01-02 | credits: nikkytok/ Adobe Stock

Um was geht es?

Wir wollen in diesem Kapitel etwas tiefer in die Materie der Vererbung vordringen und uns mit Konstruktoren im Zusammenhang mit Vererbung beschäftigen. Dieses Thema ist nicht ganz ohne, aber sehr wichtig. Halten Sie schon einmal den Kaffee bereit.

Wie funktionieren Konstruktoren bei Vererbung?

Über Konstruktoren in Java haben wir in vorherigen Kapiteln zur Objektorientierung schon einiges gelernt. So hat jede Klasse mindestens einen Konstruktor und wenn kein Konstruktor explizit deklariert wurde, versucht Java, einen parameterlosen Standard-Konstruktor bereitzustellen. Richtig interessant wird das Thema aber erst jetzt in Zusammenhang mit Vererbung!

Folgende Grundregel ist der Kern für das Verständnis:

  • Wenn wir ein Objekt einer Unterklasse erzeugen, wird im Konstruktor dieser Unterklasse der Konstruktor der Oberklasse aufgerufen. 

Verständlich wird das, wenn wir das einfach mal austesten. Hierzu lassen wir eine Unterklasse namens Siam von Katze erben, sodass wir folgende Vererbungshierarchie haben: Saeugetier <- Katze <- Siam. Anschließend erzeugen wir ein neues Siam-Objekt:

class Saeugetier {
    public Saeugetier(){
        System.out.println("Saeugetier-Konstruktor");
    }
}

class Katze extends Saeugetier {
    public Katze(){
        System.out.println("Katze-Konstruktor");
    }
}

 class Siam extends Katze {
    public Siam(){
        System.out.println("Siam-Konstruktor");
    }
}

class Playground {
   public static void main(String[] args){
       new Siam();
   }
}

Dieser Code erzeugt folgenden Print auf der Konsole:

Saeugetier-Konstruktor
Katze-Konstruktor
Siam-Konstruktor

Man sieht, dass alle Konstruktoren des Vererbungsbaums ausgeführt werden, wenn wir ein neues Unterklassen-Objekt erzeugen. Dieser Vorgang wird Konstruktorenverkettung genannt.

Genauer betrachtet passierte bei der Erzeugung des Siam-Objekts Folgendes:

  • Der Konstruktor von Siam ruft den Superklassenkonstruktor von Katze auf und dieser wiederum den Superklassenkonstruktor von Saeugetier
  • Danach werden die Anweisungen in den einzelnen Konstruktoren "von oben nach unten" nacheinander ausgeführt.

super()

Um einen Superklassenkonstruktor aufzurufen, verwendet man das Schlüsselwort super(). In unserem Beispiel von eben war der Compiler aber so freundlich und hat super() für uns ergänzt.

super() wird nämlich automatisch ausgeführt, wenn wir es bei parameterlosen Konstruktoren nicht explizit ergänzen:

public Siam(){
    super(); //nicht nötig, wird automatisch ergänzt
    System.out.println("Siam-Konstruktor");
}

super() muss die erste Anweisung des Konstruktors der Unterklasse sein (Ausnahme siehe unten).

Konstruktoren mit Parametern

Und wie funktioniert das mit einem Superklassenkonstruktor, der Parameter hat? Ganz einfach: Dann muss der Konstruktor der Unterklasse ebenfalls entsprechende Parameter haben und diese dann mit super() an den Superklassekonstruktor weiterleiten.

Hier ein Beispiel:

class Katze extends Saeugetier {
    private String name;
    public Katze(String name){
        this.name = name;
    }
}


class Siam extends Katze {
    public Siam(String name){
        super(name); //Aufruf Superklassenkontruktor
    }
}


class Playground {
   public static void main(String[] args){
       new Siam("Simba");
   }
}

Unterschied this() und super()

Diese beiden Schlüsselwörter werden oft verwechselt. Deshalb hier in Kürze der Unterschied:

  • this() ruft einen anderen Konstruktor derselben Klasse auf (Konstruktor überladen). 
  • super() ruft einen Konstruktor der direkten Superklasse auf. 

Bei der Verwendung von this() und super() müssen folgende zwei Regeln eingehalten werden:

  • In einem Konstruktor dürfen this() und super() niemals zusammen verwendet werden.. 
  • this() bzw. super() muss immer die erste Anweisung in einem Konstruktor sein. 

Sehen wir uns ein Beispiel an:

class Katze extends Saeugetier {
    private String name;
    public Katze(String name){
        this.name = name;
    }
}


class Siam extends Katze {
    //Konstruktor I
    public Siam(String name){
        super(name); //Aufruf Superklassenkonstruktor
    }

    //Konstruktor II
    public Siam(){
        this("Simba"); //Aufruf Konstruktor I
    }
}


class Playground {
   public static void main(String[] args){
       new Siam("Bailey");
       new Siam();
   }
}

Was geschieht hier? Die Klasse Siam besitzt zwei Konstruktoren (Konstruktorüberladung). Damit können wir Siam-Objekte auf zwei verschiedene Arten erzeugen: Einmal mit einem String-Argument und einmal ohne.

Bei new Siam("Bailey"); wird Konstruktor I der Klasse Siam aufgerufen, der wiederum den Konstruktor der Superklasse Katze mitsamt dem "weitergereichten" Argument "Bailey" aufruft, also super("Bailey");

Bei der Objekterzeugung new Siam(); dagegen wird Konstruktor II aufgerufen. Dieser überladene Konstruktor verweist mit this("Simba") an Konstruktor Iderselben Klasse. Dieser ruft dann wiederum den Superklassenkonstruktor mitsamt dem Argument "Simba" auf.

Werbung

Java lernen

Werde zum Java Profi!

PHP Lernen

Lerne serverbasierte Programmierung

JavaScript lernen

Skille dein Webcoding

FALCONBYTE.NET

Handmade with 🖤️

© 2018-2023 Stefan E. Heller

Impressum | Datenschutz | Changelog

Falconbyte Youtube Falconbyte GitHub facebook programmieren lernen twitter programmieren lernen discord programmieren lernen