Vererbung von Konstruktoren und Destruktoren in Java

In Java werden Konstruktoren nicht vererbt, daher müssen in einer abgeleiteten Klasse alle erforderlichen Konstruktoren erneut definiert werden.

Dabei kann mit Hilfe des Schlüsselworts super auf die Konstruktoren der Vaterklasse (Superklasse) zugegriffen und dadurch bereits vorhandener Quellcode wiederverwendet werden.

Interessierte können mit unserem Beitrag über die Grundlagen von Konstruktoren und Destruktoren in Java tiefer in die Materie eintauchen.

Dieser Beitrag hier behandelt hauptsächlich das Thema Vererbung bei Konstruktoren und Destruktoren und baut auf dem Grundlagenbeitrag auf.

Konstruktorenverkettung in Java

Wird in Java ein neues Objekt instanziert, dann wird dabei immer der zu dem verwendeten new-Operator passende Konstruktor aufgerufen. Welcher Konstruktor der Passende ist, wird von den angegebenen Parametern entschieden.

Bei dem Aufruf des passenden Konstruktors wird auch immer der Konstruktor der Vaterklasse (Superkonstruktor) aufgerufen. Dies geschieht entweder implizit oder explizit, wenn der Entwickler einen aufzurufenden Superkonstruktor festlegt.

plhq_teaser_hbox_gelb_fotolia_RA Studio_46292813

Unser großes
Android Online-Kurs
Gesamtpaket



Weitere Infos

Diese Vorgabe muss in der ersten Anweisung eines jeden Konstruktors erfolgen. Als Entwickler hat man dabei die Wahl den gewünschten Superkonstruktor vorzugeben oder einen anderen Konstruktor der eigenen Klasse aufzurufen.

Hierzu wird mit super(Parameterliste); der entsprechende Konstruktor der Vaterklasse (Superkonstruktor) und mit this(Parameterliste); der entsprechende Konstruktor der eigenen Klasse aufgerufen.

In dem folgenden Beispielprogramm werden Konstruktoren miteinander verkettet und der Konstruktor der Vaterklasse explizit aufgerufen:

Beispielanwendung für das Vererben von Konstruktoren in Java

/*
* Beispielanwendung für das Vererben von Konstruktoren in Java
*/

public class VererbungKonstruktoren
{
  public static void main (String[] args)
  {
     Tochterklasse tochter = new Tochterklasse();
     System.out.println("\nObjekt 1: " + tochter.text);
     System.out.println("Objekt 1: " + tochter.zahl);

     tochter = new Tochterklasse("Konstruktor 2 der Tochterklasse aufgerufen.");
     System.out.println("\nObjekt 2: " + tochter.text);
     System.out.println("Objekt 2: " + tochter.zahl);

     tochter = new Tochterklasse("Konstruktor 3 der Tochterklasse aufgerufen.", 50);
     System.out.println("\nObjekt 3: " + tochter.text);
     System.out.println("Objekt 3: " + tochter.zahl);

     tochter = new Tochterklasse(75);
     System.out.println("\nObjekt 4: " + tochter.text);
     System.out.println("Objekt 4: " + tochter.zahl);


     Sohnklasse sohn = new Sohnklasse();
     System.out.println("\nObjekt 5: " + sohn.text);
     System.out.println("Objekt 5: " + sohn.zahl);
  }
}


class Vaterklasse
{
  String text;

  public Vaterklasse()
  {
     this.text = "Default-Konstruktor der Vaterklasse aufgerufen.";
  }

  public Vaterklasse(String text)
  {
     this.text = text;
  }
}


class Tochterklasse extends Vaterklasse
{
  int zahl;

  public Tochterklasse()
  {
     super(); // muss nicht angegeben werden, dann würde impliziter Aufruf erfolgen 
  } 

  public Tochterklasse(String text)
  {
     super(text); // expliziter Aufruf des Superkonstruktors mit String-Parameter
  } 

  public Tochterklasse(String text, int zahl)
  {
     this(text); // Aufruf eines anderen Konstruktors der eigenen Klasse
     this.zahl = zahl;
  }

  public Tochterklasse(int zahl)
  {
     // an dieser Stelle erfolgt impliziter Aufruf des Superkonstruktors "super()" 

     this.zahl = zahl;
  } 
}


class Sohnklasse extends Vaterklasse
{
   int zahl = 100;

   // kein Konstruktor definiert, Compiler erstellt automatisch Default-Konstruktor
}

Der aufzurufende Superkonstruktor muss auch in der Vaterklasse vorhanden sein. In Zeile 60 wird mit super(text); der Superkonstruktor mit einem String-Parameter aufgerufen. Die Anweisung super(200); würde jedoch zu einem Compiler-Fehler führen, da ein Superkonstruktor mit einem int-Parameter in der Vaterklasse nicht definiert wurde.

Falls als erste Anweisung im Konstruktor kein super(Parameterliste); oder this(Parameterliste); angegeben ist, fügt der Java-Compiler an diese Stelle den impliziten Aufruf des Default-Konstruktors der Vaterklasse super(); ein. Dies wird in Zeile 71 vom Compiler durchgeführt.

Hinweis: Der parameterlose Superkonstruktor super() existiert nicht, wenn in der Superklasse nur parametrisierte Konstruktoren definiert sind. In diesem Fall wird der Default-Konstruktor vom Java-Compiler nicht zusätzlich definiert.

Wird mit this(Parameterliste);, wie in Zeile 65 mit this(text);, ein anderer Konstruktor der eigenen Klasse aufgerufen, erfolgt der Aufruf des Konstruktors der Vaterklasse von diesem heraus, entweder implizit oder explizit, wie in Zeile 60 mit super(text);.

Dadurch ist sichergestellt, dass immer als erste Anweisung ein Superkonstruktor aufgerufen wird. Dies bedeutet aber auch, dass im Konstruktor der Vaterklasse dessen Superkonstruktor automatisch als erste Anweisung aufgerufen wird.

Daher wird bei jeder Instanzierung eines Objekts eine vollständige Kette von Konstruktoren aufgerufen, vom Anfang bis zum Ende der Vererbungshierarchie. Da am Anfang eines jeden Konstruktors als erste Anweisung dessen Superkonstruktor aufgerufen wird, endet diese Verkettung immer bei dem Konstruktor der Klasse Object. Von diesem beginnend wird die Initialisierung eines Objekts nach unten in der Vererbungshierarchie ausgeführt, also von der Klasse Object beginnend über deren Unterklasse absteigend bis zu der instanzierenden Klasse.

Starten wir nun die Beispielanwendung. In der unten abgebildeten Kommandozeilenausgabe ist die resultierende Textausgabe dargestellt:

Java Vererbung von Konstruktoren

Java Vererbung von Konstruktoren – Ausgabe der Beispielanwendung

Destruktorenverkettung muss in Java explizit erfolgen

In Java werden Destruktoren eines Ableitungszweigs nicht automatisch verkettet. Es ist aber möglich, wie beim Überlagern von Methoden, den Destruktor der Vaterklasse explizit aufzurufen.

Mit der Anweisung super.finalize(); wird der Superklassendestruktor aufgerufen. Es ist aber nicht möglich den Destruktor zwei Vererbungsebenen höher aufzurufen, somit ist ein super.super.finalize(); in Java unzulässig.

plhq_teaser_hbox_gelb_fotolia_RA Studio_46292813

Unser großes
Android Online-Kurs
Gesamtpaket



Weitere Infos

Möchte man Destruktoren aber dennoch verketten, so muss in jedem Destruktor des Ableitungszweigs die Anweisung super.finalize(); angegeben werden. Dies führt zu einer expliziten Verkettung der Destruktoren bis hoch zu der Object-Klasse.


Comments 1

  1. Pingback: Vererbung und Polymorphismus in Java

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.