Für Ihren ersten Teil der Frage, die ich denke, Wikipedia bietet eine gute Definition:
In der objektorientierten Programmierung, Subtyp Polymorphismus oder Inklusion Polymorphismus ist ein Konzept in der Typentheorie, wobei ein Name Instanzen von vielen verschiedenen Klassen bezeichnen kann, solange sie durch einige gemeinsame Superklasse verwandt sind. Einschlusspolymorphismus wird im Allgemeinen durch Subtyping unterstützt, d. H. Objekte unterschiedlicher Typen sind für Objekte eines anderen Typs (ihre Basis (n)) vollständig substituierbar und können daher über eine gemeinsame Schnittstelle gehandhabt werden. Alternativ kann Einschlusspolymorphismus durch Typ Zwang, auch bekannt als Typ Casting erreicht werden.
Ein anderer Wikipedia-Artikel namens Polymorphism in object-oriented programming scheint Ihre Fragen sehr gut zu beantworten. Die zweite Referenz in diesem Artikel mit der Bezeichnung On Understanding Types, Data Abstraction, and Polymorphism deckt dieses Thema ebenfalls sehr detailliert ab.
Diese Untertypisierung in Java wird unter anderem durch Vererbung von Klassen und Schnittstellen erreicht. Obwohl die Subtyping-Features von Java möglicherweise nicht immer in Bezug auf die Vererbung erkennbar sind. Nehmen wir zum Beispiel die Fälle von Kovarianz und Kontravarianz mit Generika. Arrays sind auch serialisierbar und kopierbar, obwohl dies nirgendwo in der Typhierarchie offensichtlich ist. Es kann auch gesagt werden, dass durch die primitive Verbreiterungskonvertierung auch numerische Typen in Java polymorph sind. Und der Operator verhält sich abhängig von seinen Operanden polymorph.
In jedem Fall spielt die Vererbung eine wichtige Rolle bei der Umsetzung einiger dieser Polymorphismen.
Überlastung vs Zwingende
Ihre zweite Teil der Frage scheint über die Wahl der Implementierung einer bestimmten Methode. Wenn eine Klasse eine Methode überschreibt und Sie eine Instanz dieser Klasse erstellen, möchten Sie offensichtlich, dass die überschriebene Version der Methode aufgerufen wird, selbst wenn Sie über eine Referenz der übergeordneten Klasse auf das Objekt zugreifen.
Die Auswahl der richtigen Implementierung der Methode erfolgt zur Laufzeit, wie Sie genau hinwiesen, jetzt wird die Signatur der Methode, die aufgerufen werden soll, zur Kompilierzeit entschieden. Da es beim Überladen um verschiedene Methoden mit dem gleichen Namen und unterschiedlicher Signatur geht, wird gesagt, dass die Überschreibung der Methoden zur Kompilierungszeit erfolgt.
Aufschalten Methodenauswahl zur Kompilierzeit
Die Java Language Specification (JLS) in Abschnitt 15.12 Method Invocation Expressions im Detail erläutert den Prozess, der der Compiler die richtige Methode zur Auswahl folgt aufzurufen.
Dort werden Sie feststellen, dass dies eine Kompilierzeit Aufgabe ist. Die JLS sagt in Abschnitt 15.12.2:
Dieser Schritt verwendet die Namen der Methode und die Typen des Arguments Ausdrücke Methoden zu finden, die sowohl zugänglich und anwendbar sind Es kann mehr als eine solche Methode, in diesem Fall wird die spezifischste gewählt.
Um die Kompilierzeit zu überprüfen, können Sie den folgenden Test durchführen.
Deklarieren Sie eine Klasse wie diese und kompilieren Sie sie.
public class ChooseMethod {
public void doSomething(Number n){
System.out.println("Number");
}
}
Deklarieren Sie eine zweite Klasse, die eine Methode der ersten aufruft und kompilieren Sie sie.
public class MethodChooser {
public static void main(String[] args) {
ChooseMethod m = new ChooseMethod();
m.doSomething(10);
}
}
Wenn Sie die Haupt aufrufen, sagt der Ausgang Number
. Jetzt
, fügen Sie eine zweite speziellere überlastet Methode zum ChooseMethod
Klasse und neu kompilieren (aber nicht die andere Klasse neu kompilieren).
public void doSomething(Integer i) {
System.out.println("Integer");
}
Wenn Sie die Haupt erneut ausführen, ist der Ausgang noch Number
.
Grundsätzlich, weil es zur Kompilierzeit entschieden wurde. Wenn Sie die Klasse MethodChooser
(die mit der Hauptkomponente) neu kompilieren und das Programm erneut ausführen, lautet die Ausgabe Integer
.
Wenn Sie also die Auswahl einer der überladenen Methoden erzwingen möchten, muss der Typ der Argumente zum Zeitpunkt der Kompilierung und nicht nur zur Laufzeit dem Typ der Parameter entsprechen.
zur Laufzeit Methodenauswahl Aufschalten
Auch hier wird die Signatur der Methode bei der Kompilierung entschieden, aber die tatsächliche Umsetzung wird zur Laufzeit entschieden.
Deklarieren Sie eine Klasse wie diese und kompilieren Sie sie.
public class ChooseMethodA {
public void doSomething(Number n){
System.out.println("Number A");
}
}
Dann eine zweite Verlängerung Klasse deklarieren und kompilieren:
public class ChooseMethodB extends ChooseMethodA { }
Und in der MethodChooser Klasse, die Sie tun:
public class MethodChooser {
public static void main(String[] args) {
ChooseMethodA m = new ChooseMethodB();
m.doSomething(10);
}
}
Und wenn Sie es ausführen erhalten Sie die Ausgabe Number A
und Dies ist in Ordnung, da das Verfahren wird in ChooseMethodB
und daher wird die Implementierung ist, dass die ChooseMethodA
aufgerufen nicht außer Kraft gesetzt worden ist.
public void doSomething(Number n){
System.out.println("Number B");
}
und neu kompilieren gerade diese, und das Hauptverfahren erneut aus:
nun eine überschriebene Methode in MethodChooserB
hinzuzufügen.
Jetzt erhalten Sie die Ausgabe Number B
Als solche wurde die Implementierung zur Laufzeit gewählt, und nicht die Neuübersetzung der MethodChooser
Klasse erforderlich war.
Ich denke, Überladung hat nichts mit Polymorphie zu tun. – ka3ak
Eigentlich ist dies eine Form des Pollymorphismus: Aus Wikipedia: Der Begriff Ad-hoc-Polymorphismus bezieht sich auf polymorphe Funktionen, die auf Argumente unterschiedlicher Typen angewendet werden können, sich aber je nach Art des Arguments unterschiedlich verhalten (auch bekannt als Überlastung der Funktion oder Überlastung des Operators). –
@edalorzo: faktische Genauigkeit von http://en.wikipedia.org/wiki/Ad-hoc_polymorphism ist umstritten. – Jayan