Das Wort Polymorphismus wird in verschiedenen Kontexten verwendet und beschreibt Situationen, in denen etwas in verschiedenen Formen auftritt. In der Informatik beschreibt es das Konzept, dass auf Objekte verschiedener Typen über dieselbe Schnittstelle zugegriffen werden kann. Jeder Typ kann eine eigene, unabhängige Implementierung dieser Schnittstelle bereitstellen. Es ist eines der Kernkonzepte der objektorientierten Programmierung (OOP).,
Wenn Sie sich fragen, ob ein Objekt polymorph ist, können Sie einen einfachen Test durchführen. Wenn das Objekt mehrere is-a-oder instanceof-Tests erfolgreich besteht, ist es polymorph. Wie ich in meinem Beitrag über Vererbung beschrieben habe, erweitern alle Java-Klassen das Klassenobjekt. Aus diesem Grund sind alle Objekte in Java polymorph, da sie mindestens zwei instanceof Prüfungen bestehen.,
Verschiedene Arten von Polymorphismus
Java unterstützt 2 Arten von Polymorphismus:
- statisch oder Kompilierzeit
- dynamisch
Statischer Polymorphismus
Java ermöglicht es Ihnen, wie viele andere objektorientierte Programmiersprachen, mehrere Methoden innerhalb derselben Klasse zu implementieren, die denselben Namen, aber einen anderen Satz von Parametern verwenden. Das nennt man Methodenüberladung und stellt eine statische Form des Polymorphismus dar.,
Die Parametersätze müssen sich in mindestens einem der folgenden drei Kriterien unterscheiden:
- Sie müssen eine andere Anzahl von Parametern haben, z. B. akzeptiert eine Methode 2 und eine andere 3 Parameter.
- Die Typen der Parameter müssen unterschiedlich sein, z. B. akzeptiert eine Methode eine Zeichenfolge und eine andere eine lange.
- Sie müssen die Parameter in einer anderen Reihenfolge erwarten, z. B. akzeptiert eine Methode eine Zeichenfolge und eine lange und eine andere eine lange und eine Zeichenfolge. Diese Art der Überlastung wird nicht empfohlen, da dies das Verständnis der API erschwert.,
In den meisten Fällen bietet jede dieser überladenen Methoden eine andere, aber sehr ähnliche Funktionalität.
Aufgrund der unterschiedlichen Parametersätze hat jede Methode eine andere Signatur. Dadurch kann der Compiler identifizieren, welche Methode aufgerufen werden muss, und sie an den Methodenaufruf binden. Dieser Ansatz wird als statische Bindung oder statischer Polymorphismus bezeichnet.
schauen wir uns ein Beispiel an.
Ein einfaches Beispiel für statischen Polymorphismus
Ich verwende dasselbe CoffeeMachine-Projekt wie in den vorherigen Beiträgen dieser Serie. Sie können es unter https://github.com/thjanssen/Stackify-OopInheritanceklonen.,
Die BasicCoffeeMachine Klasse implementiert zwei Methoden mit dem Namen brewCoffee. Der erste akzeptiert einen parameter vom Typ CoffeeSelection. Die andere Methode akzeptiert zwei Parameter, eine CoffeeSelection und ein int.
Wenn Sie nun eine dieser Methoden aufrufen, identifiziert der bereitgestellte Parametersatz die Methode, die aufgerufen werden muss.
Im folgenden Code-Snippet rufe ich die Methode nur mit einem CoffeeSelection-Objekt auf. Zur Kompilierungszeit bindet der Java-Compiler diesen Methodenaufruf an die brewCoffee-Methode(CoffeeSelection selection).,
BasicCoffeeMachine coffeeMachine = createCoffeeMachine();coffeeMachine.brewCoffee(CoffeeSelection.FILTER_COFFEE);
Wenn ich diesen Code ändere und die brewCoffee-Methode mit einem CoffeeSelection-Objekt und einem int aufrufe, bindet der Compiler den Methodenaufruf an die andere brewCoffee-Methode(CoffeeSelection selection, int number).
Dynamischer Polymorphismus
Diese Form des Polymorphismus erlaubt es dem Compiler nicht, die ausgeführte Methode zu bestimmen. Die JVM muss das zur Laufzeit tun.
Innerhalb einer Vererbungshierarchie kann eine Unterklasse eine Methode ihrer Oberklasse überschreiben. Dadurch kann der Entwickler der Unterklasse das Verhalten dieser Methode anpassen oder vollständig ersetzen.,
Es erzeugt auch eine Form von Polymorphismus. Beide Methoden, die von der Super – und Unterklasse implementiert werden, haben denselben Namen und dieselben Parameter, bieten jedoch unterschiedliche Funktionen.
Schauen wir uns ein weiteres Beispiel aus dem CoffeeMachine-Projekt an.
Methode Überschreiben in einer Vererbungshierarchie
Die BasicCoffeeMachine Klasse ist die Oberklasse der PremiumCoffeeMachine Klasse.
Beide Klassen bieten eine Implementierung der brewCoffee-Methode(CoffeeSelection selection).,
Wenn Sie den Beitrag über die Vererbung des OOP-Konzepts lesen, kennen Sie bereits die beiden Implementierungen der brewCoffee-Methode. Die BasicCoffeeMachine unterstützt nur die CoffeeSelection.FILTERKAFFEE. Die brewCoffee-Methode der PremiumCoffeeMachine-Klasse unterstützt CoffeeSelection.ESPRESSO. Wenn es mit einer anderen CoffeeSelection aufgerufen wird, verwendet es das Schlüsselwort super, um den Aufruf an die Oberklasse zu delegieren.,
Späte Bindung
Wenn Sie eine solche Vererbungshierarchie in Ihrem Projekt verwenden möchten, müssen Sie die folgende Frage beantworten können: Welche Methode wird die JVM aufrufen?
Das kann nur zur Laufzeit beantwortet werden, da es von dem Objekt abhängt, von dem die Methode aufgerufen wird. Der Typ der Referenz, den Sie in Ihrem Code sehen können, ist irrelevant. Sie müssen drei allgemeine Szenarien unterscheiden:
- Ihr Objekt ist vom Typ der Oberklasse und wird als Oberklasse referenziert., Im Beispiel dieses Beitrags wird also auf ein BasicCoffeeMachine-Objekt als BasicCoffeeMachine verwiesen.
- Ihr Objekt ist vom Typ der Unterklasse und wird als Unterklasse referenziert. Im Beispiel dieses Beitrags wird auf ein PremiumCoffeeMachine-Objekt als PremiumCoffeeMachine verwiesen.
- Ihr Objekt ist vom Typ der Unterklasse und wird als Oberklasse referenziert. Im CoffeeMachine-Beispiel wird auf ein PremiumCoffeeMachine-Objekt als BasicCoffeeMachine verwiesen.
Oberklasse referenziert als Oberklasse
Das erste Szenario ist ziemlich einfach., Wenn Sie ein BasicCoffeeMachine-Objekt instanziieren und in einer Variablen vom Typ BasicCoffeeMachine speichern, ruft die JVM die brewCoffee-Methode für die BasicCoffeeMachine-Klasse auf. Sie können also nur einen Kaffee brauenauswahl.FILTERKAFFEE.
Unterklasse referenziert als Unterklasse
Das zweite Szenario ist ähnlich. Aber dieses Mal instanziiere ich eine PremiumCoffeeMachine und verweise sie als PremiumCoffeeMachine. In diesem Fall ruft die JVM die brewCoffee-Methode der PremiumCoffeeMachine-Klasse auf, die CoffeeSelection unterstützt.ESPRESSO.,
Unterklasse, auf die als Oberklasse verwiesen wird
Dies ist das interessanteste Szenario und der Hauptgrund, warum ich dynamischen Polymorphismus in solchen Details erkläre.
Wenn Sie ein PremiumCoffeeMachine-Objekt instanziieren und es der Variablen BasicCoffeeMachine coffeeMachine zuweisen, handelt es sich immer noch um ein PremiumCoffeeMachine-Objekt. Es sieht nur wie eine BasicCoffeeMachine aus.
Der Compiler sieht das nicht im Code, und Sie können nur die von der BasicCoffeeMachine Klasse bereitgestellten Methoden verwenden., Wenn Sie jedoch die brewCoffee-Methode für die coffeeMachine-Variable brewCoffee, weiß die JVM, dass es sich um ein Objekt vom Typ PremiumCoffeeMachine handelt, und führt die überschriebene Methode aus. Dies wird als späte Bindung bezeichnet.
Zusammenfassung
Polymorphismus ist eines der Kernkonzepte in OOP-Sprachen. Es beschreibt das Konzept, dass verschiedene Klassen mit derselben Schnittstelle verwendet werden können. Jede dieser Klassen kann eine eigene Implementierung der Schnittstelle bereitstellen.
Java unterstützt zwei Arten von Polymorphismus. Sie können eine Methode mit verschiedenen Parametersätzen überladen., Dies wird als statischer Polymorphismus bezeichnet, da der Compiler den Methodenaufruf statisch an eine bestimmte Methode bindet.
Innerhalb einer Vererbungshierarchie kann eine Unterklasse eine Methode ihrer Oberklasse überschreiben. Wenn Sie die Unterklasse instanziieren, ruft die JVM immer die überschriebene Methode auf, auch wenn Sie die Unterklasse in ihre Oberklasse umwandeln. Das nennt man dynamischen Polymorphismus.