Vererbung und Polymorphismus in Java


In Java können mit Hilfe der Vererbung Programmteile wiederverwendet werden, dabei werden die Merkmale bereits vorhandener Klassen auf abgeleitete Klassen übertragen. Unser Beitrag Vererbung in Java – Ableiten einer Klassen behandelt die Grundlagen der Vererbung.

Das Konzept der Vererbung ist in Java auf Einfachvererbung begrenzt, das heißt eine neue Klasse kann maximal von einer anderen Klasse abgeleitet werden. Andere objektorientierte Programmiersprachen verfügen über die Möglichkeit der Mehrfachvererbung, bei der eine Klasse von mehreren Klassen abgeleitet werden kann. Da dies aber auch Probleme mit sich bringt, wurde in Java nur die Einfachvererbung implementiert.

Es gibt in Java aber durchaus das Konzept der Mehrfachvererbung. Und zwar wurde mit Hilfe der Interfaces eine restriktive Art der Mehrfachvererbung geschaffen.

Überlagern von Methoden und dynamisches Binden in Java

In Java werden Methoden der Vaterklasse an die abgeleiteten Klassen vererbt. Die vererbten Methoden können dann in den abgeleiteten Klassen neu definiert werden. Dieser Vorgang wird in Java als das Überlagern von Methoden bezeichnet.

Zusätzlich können in den Tochterklassen neue Methoden definiert oder die geerbten Methoden unverändert übernommen werden. Somit können in einer abgeleiteten Klasse drei Arten von Methoden vorhanden sein:

  • In der Tochterklasse definierte neue Methoden
  • Von der Vaterklasse geerbte unveränderte Methoden
  • Von der Vaterklasse geerbte überlagerte Methoden, die in der Tochterklasse neu definiert wurden

Wurde eine Methode überlagert (d.h. in der abgeleiteten Klasse neu definiert), wird beim Aufrufen der Methode auf Objekten dieses Datentyps immer die überlagerte Version verwendet.

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 Vererbung von Konstruktoren und Destruktoren in Java tiefer in die Materie eintauchen.

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. Diese Vorgabe muss in der ersten Anweisung eines jeden Konstruktors erfolgen.

Polymorphismus und Konstruktoren in Java

Polymorphe Methodenaufrufe können in Konstruktoren zu schwerwiegenden Programmfehlern führen, die sehr schwierig zu lokalisieren sind.

Aufgrund der Initialisierungsreihenfolge von Konstruktoren besteht die Gefahr, dass Variablen der abgeleiteten Klasse noch nicht initialisiert wurden, die polymorph aufgerufenen überlagerten Methoden diese Variablen jedoch schon verwenden.

Daher sollten Aufrufe von Methoden, welche möglicherweise in Subklassen überlagert werden, nicht in Konstruktoren erfolgen. Zur Veranschaulichung habe wir eine Beispielanwendung für polymorphe Methodenaufrufe in Konstruktoren erstellt, bei der eine unvollständige Variableninitialisierung auftritt.

Die Initialisierungsreihenfolge von Konstruktoren sollte jedem Java-Entwickler bestens bekannt sein. Wir behandeln sie in unserem Beitrag: Konstruktoren und Destruktoren in Java ausführlich, an dieser Stelle soll uns aber die folgende kurze Beschreibung genügen.

In Java werden bei jeder Instanzierung die folgenden beiden Schritte ausgeführt:

  1. Die Konstruktoren der Vaterklassen werden aufgerufen (von der eigenen Klasse bis hoch zur Urklasse object). Dabei werden die Variablen der Vaterklassen initialisiert und anschließend die Anweisungen in den Vaterklassen-Konstruktoren ausgeführt.
  2. Danach werden die Variablen der eigenen Klasse initialisiert und die Anweisungen des eigenen Konstruktors ausgeführt.

Wird nun in einem Konstruktor einer Vaterklasse eine Methode aufgerufen, die in einer abgeleiteten Klasse überlagert wurde, sind zu diesem Zeitpunkt die Variablen der Klasse noch nicht initialisiert. Dies würde erst später in Schritt 2 erfolgen, wenn der Konstruktor der abgeleiteten Klasse ausgeführt wird.

In unserem nächsten Beitrag behandeln wir das spannende Thema: Interfaces (Schnittstellen) in Java. Interfaces können als Ersatzkonstrukt für Mehrfachvererbung gesehen werden. Eine Klasse kann mehrere Interfaces implementieren, d.h. ihr können mehrere Schnittstellen zur Verfügung gestellt werden. Jede dieser Schnittstellen (Interfaces) muss aber von der Klasse vollständig implementiert werden.

Der folgende Link führt euch zurück zum Programmierkurs für Java-Beginner.

Comments 1

  1. Pingback: Klassen in Java: Die Grundlagen der objektorientierten Programmierung

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *