Die Polymorphie (griech. Vielgestaltigkeit) bezeichnet in der objektorientierten Programmierung den Prozess, dass Methoden mit identischer Signatur unterschiedliche Resultate liefern. Dieses Phänomen tritt insbesondere im Kontext der Vererbung auf. Es wird zwischen statischer Polymorphie (überladene Methoden) und dynamischer Polymorphie (überschriebene Methoden) unterschieden.
Erklärung
Die Polymorphie ist ein grundlegendes Konzept der objektorientierten Programmierung, welches viel Arbeit sparen kann. Gleichzeitig kann die Polymorphie jedoch unerwünschtes Verhalten im Programm bescheren, was eine langwierige Fehlersuche nach sich zieht.
Das Wort Polymorphie kommt aus dem Griechischen und bedeutet Vielgestaltigkeit. Das Phänomen der Polymorphie kennst du bereits aus dem allgemeinen Sprachgebrauch. Wörter wie "Bank" oder "Flügel" können abhängig vom Kontext sehr unterschiedliche Bedeutungen haben:
- Ich bringe mein Geld zur Bank.
- Ich setzte mich auf die Bank.
Oder:
- Ein Vogel hat zwei Flügel.
- Er spielte das Lied auf seinem Flügel.
In der Informatik gibt es ebenfalls eine solche überladene Bedeutung von Wörtern. Polymorphie tritt dabei im Zusammenhang mit Methoden auf. Es werden grundlegend zwei Arten der Polymorphie unterschieden: statische Polymorphie und dynamische Polymorphie.
Statische Polymorphie
Die statische Polymorphie bezeichnet die Mehrfachbelegung von Methodennamen. Gegeben sei folgender Quellcode. Es gibt die Klasse Greetings
, welche zwei Methoden namens print
beinhaltet. Diese beiden Methoden tragen denselben Namen, sie unterscheiden sich nur anhand der Parameter, die übergeben werden:
In Java muss der Compiler immer in der Lage sein eine Methode anhand ihrer Namen eindeutig zu identifizieren. Statische Polymorphie ermöglicht es dir nun, mehrere Methoden mit gleichen Namen zu definieren. Die Identifikation findet dadurch auch über die Übergabeparameter statt.
Besuche die App, um alle Inhalte zu sehen!
Der Methodenname print
ist dabei doppelt belegt. Einmal exisitert die Methode print
nur mit dem Parameter text
. Die zweite print
-Methode nimmt jedoch die Paramter text
und name
entgegen.
Welche Methode print
aufgerufen wird, entscheidet Java also ausschließlich auf Basis der Übergabeparameter. Wird ein Parameter übergeben, so wird die erste print
-Methode mit nur einem Parameter aufgerufen. Werden zwei Parameter übergeben, so die zweite print
-Methode.
Dynamische Polymorphie
Die dynamische Polymorphie beschreibt die Überlagerung von gleichen Methoden im Kontext der Vererbung. Es wird dann zur Laufzeit entschieden, welche Methode aufgerufen wird.
Kindklassen erben immer alle Methoden der Elternklasse. Wenn du eine Methode in der Kindklasse durch dynamische Polymorphie neu definierst, so wird die Methode der Elternklasse ersetzt und stattdessen die neue Methode verwendet. Dynamische Polymorphie ermöglicht also spezialisiertere Methoden in den Kindklassen.
Betrachte folgende Vererbung:
Die Klassen Square
und Triangle
erben von der Klasse Shape
. Die Klasse Triangle
überschreibt dabei die info()
-Methode der Klasse Shape
. Die Klasse Square
erhält eine eigene infoSquare()
-Methode.
Betrachte dazu folgenden Quellcode:
Besuche die App, um alle Inhalte zu sehen!
Die Methode main
erzeugt nun mehrere Objekte von den verschiedenen Klassen und ruft auf diesen die info
- Methoden auf. Durch dynamische Polymorphie kommt es zu verschiedenem Verhalten, teilweise sogar zu Error-Meldungen.
Objekt: Shape a
Besuche die App, um alle Inhalte zu sehen!
Shape a ist ein Objekt der Klasse Shape
und ist in einer Shape
-Variable gespeichert. Auf dem Objekt a
ruft die info()
-Methode die info()
-Methode der Klasse Shape auf. Es kommt zu keiner dynamischen Polymorphie.
Objekt: Shape b
Besuche die App, um alle Inhalte zu sehen!
Shape b ist ein Objekt der Klasse Triangle
und ist in einer Shape
-Variable gespeichert. Auf dem Objekt b
ruft die info()
-Methode die info()
-Methode der Klasse Triangle auf. Es kommt zu einer dynamischen Polymorphie, da die info()
-Methode der Klasse Triangle
die info()
-Methode der Klasse Shape
überschreibt.
Objekt: Shape c
Besuche die App, um alle Inhalte zu sehen!
Shape c ist ein Objekt der Klasse Square
und ist in einer Shape
-Variable gespeichert. Auf dem Objekt c
ruft die info()
-Methode die info()
-Methode der Klasse Shape auf, die Klasse Square
diese von Shape
geerbt hat.
Es kommt jedoch zu einer Error-Meldung, da c.squareInfo()
nicht auf einem Objekt des Types Shape
aufgerufen werden kann. Der Typ des Objektes der Variable (hier Shape
) definiert also, welche Methoden und Variablen das Objekt hat.
Objekt: Square d
Besuche die App, um alle Inhalte zu sehen!
Shape d ist ein Objekt der Klasse Square
in einer Square
Variable gespeichert. Auf dem Objekt d
ruft die info()
-Methode die info()
-Methode der Klasse Shape auf, da diese verbt wurde.
Es kommt zu keiner dynamischen Polymorphie, da die info()
-Methode der Klasse Shape
nicht namesgleich mit der squareInfo()
-Methode der Klasse Square
ist und daher keine Überschreibung stattfindet.
Der Compiler denkt mit - Fun Fact
Das Schlagwort @Override kennzeichnet, wenn Methoden der Kinderklassen Methoden der Elternklasse überschreiben. Das Schlagwort ist jedoch nicht verpflichtend!
Ältere Compiler ignorieren dieses Schlagwort oft vollständig und entscheiden selbst, ob Polymorphie vorliegt oder nicht.
Moderne Compiler jedoch liefern einen Hinweis, wenn eine Methode mit @Override
gekennzeichnet wurde, aber keine Polymorphie vorliegt. Wenn sich also zum Beispiel ein Tippfehler in einer der Methodennamen befindet (und durch die fehlende Namensgleichheit die Polymorphie nicht vorhanden wäre), erkennt der Compiler, dass eigentlich Polymorphie geplant vorliegen müsste. So kannst du einen Fehler korrigieren, bevor er später zu Problemen führt.