Kann jemand ein einfaches Beispiel liefern, das den Unterschied zwischen dynamischem und statischem Polymorphismus in Java erklärt?
Kann jemand ein einfaches Beispiel liefern, das den Unterschied zwischen dynamischem und statischem Polymorphismus in Java erklärt?
Antworten:
Polymorphismus
1. Statische Bindung / Compile-Time-Bindung / Early Binding / Methodenüberladung (in derselben Klasse)
2. Dynamische Bindung / Laufzeitbindung / Späte Bindung / Überschreiben von Methoden (in verschiedenen Klassen)
class Calculation {
void sum(int a,int b){System.out.println(a+b);}
void sum(int a,int b,int c){System.out.println(a+b+c);}
public static void main(String args[]) {
Calculation obj=new Calculation();
obj.sum(10,10,10); // 30
obj.sum(20,20); //40
}
}
class Animal {
public void move(){
System.out.println("Animals can move");
}
}
class Dog extends Animal {
public void move() {
System.out.println("Dogs can walk and run");
}
}
public class TestDog {
public static void main(String args[]) {
Animal a = new Animal(); // Animal reference and object
Animal b = new Dog(); // Animal reference but Dog object
a.move();//output: Animals can move
b.move();//output:Dogs can walk and run
}
}
Animal reference but Dog object
, warum können wir nicht verwenden Dog reference and dog object
?
Methodenüberladung wäre ein Beispiel für statischen Polymorphismus
Das Überschreiben wäre ein Beispiel für dynamischen Polymorphismus.
Denn im Falle einer Überladung weiß der Compiler zur Kompilierungszeit, welche Methode mit dem Aufruf verknüpft werden muss. Es wird jedoch zur Laufzeit für den dynamischen Polymorphismus bestimmt
Dynamischer (Laufzeit-) Polymorphismus ist der zur Laufzeit vorhandene Polymorphismus. Hier versteht der Java-Compiler nicht, welche Methode zur Kompilierungszeit aufgerufen wird. Nur JVM entscheidet, welche Methode zur Laufzeit aufgerufen wird. Das Überladen von Methoden und das Überschreiben von Methoden mithilfe von Instanzmethoden sind Beispiele für dynamischen Polymorphismus.
Beispielsweise,
Stellen Sie sich eine Anwendung vor, die verschiedene Dokumenttypen serialisiert und de-serialisiert.
Wir können 'Dokument' als Basisklasse und verschiedene daraus abgeleitete Dokumenttypklassen haben. ZB XMLDocument, WordDocument usw.
Die Dokumentklasse definiert die Methoden 'Serialize ()' und 'De-serialize ()' als virtuell, und jede abgeleitete Klasse implementiert diese Methoden auf ihre eigene Weise basierend auf dem tatsächlichen Inhalt der Dokumente.
Wenn verschiedene Dokumenttypen serialisiert / de-serialisiert werden müssen, werden die Dokumentobjekte durch die Klassenreferenz (oder den Zeiger) 'Document' referenziert, und wenn die Methode 'Serialize ()' oder 'De-serialize ()' aufgerufen wird Darauf werden entsprechende Versionen der virtuellen Methoden aufgerufen.
Statischer Polymorphismus (Kompilierungszeit) ist der Polymorphismus, der zur Kompilierungszeit gezeigt wird. Hier weiß der Java-Compiler, welche Methode aufgerufen wird. Methodenüberladung und Methodenüberschreibung mit statischen Methoden; Methodenüberschreibungen mit privaten oder endgültigen Methoden sind Beispiele für statischen Polymorphismus
Beispielsweise,
Ein Mitarbeiterobjekt kann zwei print () -Methoden haben, eine ohne Argumente und eine mit einer Präfixzeichenfolge, die zusammen mit den Mitarbeiterdaten angezeigt wird.
Wenn angesichts dieser Schnittstellen die print () -Methode ohne Argumente aufgerufen wird, weiß der Compiler anhand der Funktionsargumente, welche Funktion aufgerufen werden soll, und generiert den Objektcode entsprechend.
Weitere Informationen finden Sie unter "Was ist Polymorphismus" (Google it).
Die Bindung bezieht sich auf die Verknüpfung zwischen Methodenaufruf und Methodendefinition.
Dieses Bild zeigt deutlich, was bindend ist.
In diesem Bild ist der Aufruf von "a1.methodOne ()" an die entsprechende Definition von methodOne () und der Aufruf von "a1.methodTwo ()" an die entsprechende Definition von methodTwo () gebunden.
Für jeden Methodenaufruf sollte eine korrekte Methodendefinition vorhanden sein. Dies ist eine Regel in Java. Wenn der Compiler nicht für jeden Methodenaufruf die richtige Methodendefinition sieht, wird ein Fehler ausgegeben.
Kommen Sie nun zu statischer Bindung und dynamischer Bindung in Java.
Statische Bindung in Java:
Statische Bindung ist eine Bindung, die während der Kompilierung auftritt. Es wird auch als frühe Bindung bezeichnet, da die Bindung erfolgt, bevor ein Programm tatsächlich ausgeführt wird
.
Die statische Bindung kann wie im folgenden Bild gezeigt werden.
In diesem Bild ist 'a1' eine Referenzvariable vom Typ Klasse A, die auf ein Objekt der Klasse A zeigt. 'A2' ist ebenfalls eine Referenzvariable vom Typ Klasse A, zeigt jedoch auf ein Objekt der Klasse B.
Während der Kompilierung überprüft der Compiler während der Bindung nicht den Objekttyp, auf den eine bestimmte Referenzvariable zeigt. Es wird lediglich der Typ der Referenzvariablen überprüft, über die eine Methode aufgerufen wird, und es wird geprüft, ob in diesem Typ eine Methodendefinition dafür vorhanden ist.
Beispielsweise prüft der Compiler für den Methodenaufruf "a1.method ()" im obigen Bild, ob eine Methodendefinition für method () in Klasse A vorhanden ist. Da 'a1' vom Typ Klasse A ist. In ähnlicher Weise wird beim Methodenaufruf "a2.method ()" geprüft, ob in Klasse A eine Methodendefinition für method () vorhanden ist. Da 'a2' auch vom Typ Klasse A ist. Es wird nicht überprüft, auf welches Objekt 'a1' und 'a2' zeigen. Diese Art der Bindung wird als statische Bindung bezeichnet.
Dynamische Bindung in Java:
Dynamische Bindung ist eine Bindung, die zur Laufzeit erfolgt. Es wird auch als späte Bindung bezeichnet, da die Bindung erfolgt, wenn das Programm tatsächlich ausgeführt wird.
Zur Laufzeit werden tatsächliche Objekte zum Binden verwendet. Zum Beispiel wird für den Aufruf von "a1.method ()" im obigen Bild die Methode () des tatsächlichen Objekts aufgerufen, auf das 'a1' zeigt. Beim Aufruf von "a2.method ()" wird method () des tatsächlichen Objekts aufgerufen, auf das 'a2' zeigt. Diese Art der Bindung wird als dynamische Bindung bezeichnet.
Die dynamische Bindung des obigen Beispiels kann wie unten gezeigt werden.
Polymorphismus: Polymorphismus ist die Fähigkeit eines Objekts, viele Formen anzunehmen. Die häufigste Verwendung von Polymorphismus in OOP tritt auf, wenn eine übergeordnete Klassenreferenz verwendet wird, um auf ein untergeordnetes Klassenobjekt zu verweisen.
Dynamische Bindung / Laufzeitpolymorphismus:
Laufzeit-Polymorphismus, auch als Methodenüberschreibung bezeichnet. In diesem Mechanismus wird ein Aufruf einer überschriebenen Funktion zur Laufzeit aufgelöst.
public class DynamicBindingTest {
public static void main(String args[]) {
Vehicle vehicle = new Car(); //here Type is vehicle but object will be Car
vehicle.start(); //Car's start called because start() is overridden method
}
}
class Vehicle {
public void start() {
System.out.println("Inside start method of Vehicle");
}
}
class Car extends Vehicle {
@Override
public void start() {
System.out.println("Inside start method of Car");
}
}
Ausgabe:
Innenstartmethode des Autos
Statischer Bindungs- / Kompilierungszeitpolymorphismus:
Welche Methode aufgerufen werden soll, wird nur zur Kompilierungszeit entschieden.
public class StaticBindingTest {
public static void main(String args[]) {
Collection c = new HashSet();
StaticBindingTest et = new StaticBindingTest();
et.sort(c);
}
//overloaded method takes Collection argument
public Collection sort(Collection c){
System.out.println("Inside Collection sort method");
return c;
}
//another overloaded method which takes HashSet argument which is sub class
public Collection sort(HashSet hs){
System.out.println("Inside HashSet sort method");
return hs;
}
}
Ausgabe: Innerhalb der Sammlung sortieren Metho
Das Überladen von Methoden ist ein Beispiel für Kompilierungszeit / statischen Polymorphismus, da die Methodenbindung zwischen Methodenaufruf und Methodendefinition zur Kompilierungszeit erfolgt und von der Referenz der Klasse abhängt (Referenz wird zur Kompilierungszeit erstellt und geht zum Stapel).
Das Überschreiben von Methoden ist ein Beispiel für Laufzeit / dynamischen Polymorphismus, da die Methodenbindung zwischen Methodenaufruf und Methodendefinition zur Laufzeit erfolgt und vom Objekt der Klasse abhängt (Objekt, das zur Laufzeit erstellt wird und zum Heap wechselt).
In einfachen Worten :
Statischer Polymorphismus : Der gleiche Methodenname wirdmit unterschiedlichen Typen oder Anzahlen von Parametern in derselben Klasse (unterschiedliche Signatur) überladen . Der gezielte Methodenaufruf wird zur Kompilierungszeit aufgelöst.
Dynamischer Polymorphismus : Dieselbe Methode wirdin verschiedenen Klassen mit derselben Signatur überschrieben . Der Objekttyp, für den die Methode aufgerufen wird, ist zur Kompilierungszeit nicht bekannt, wird jedoch zur Laufzeit festgelegt.
Im Allgemeinen wird Überladung nicht als Polymorphismus betrachtet.
Von der Java-Tutorial- Seite :
Unterklassen einer Klasse können ihr eigenes eindeutiges Verhalten definieren und dennoch einige der gleichen Funktionen der übergeordneten Klasse gemeinsam nutzen
Generally overloading won't be considered as polymorphism.
Können Sie bitte auf diesen Punkt näher eingehen?
Das Überladen von Methoden wird als statischer Polymorphismus bezeichnet und auch als Polymorphismus der Kompilierungszeit oder statische Bindung bezeichnet, da überladene Methodenaufrufe zur Kompilierungszeit vom Compiler auf der Grundlage der Argumentliste und der Referenz, für die wir die Methode aufrufen, aufgelöst werden.
Das Überschreiben von Methoden wird als dynamischer Polymorphismus oder einfacher Polymorphismus oder Laufzeit-Methodenversand oder dynamische Bindung bezeichnet, da überschriebene Methodenaufrufe zur Laufzeit aufgelöst werden.
Um zu verstehen, warum dies so ist, nehmen wir ein Beispiel Mammal
und eine Human
Klasse
class Mammal {
public void speak() { System.out.println("ohlllalalalalalaoaoaoa"); }
}
class Human extends Mammal {
@Override
public void speak() { System.out.println("Hello"); }
public void speak(String language) {
if (language.equals("Hindi")) System.out.println("Namaste");
else System.out.println("Hello");
}
}
Ich habe die Ausgabe sowie den Bytecode der folgenden Codezeilen eingefügt
Mammal anyMammal = new Mammal();
anyMammal.speak(); // Output - ohlllalalalalalaoaoaoa
// 10: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V
Mammal humanMammal = new Human();
humanMammal.speak(); // Output - Hello
// 23: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V
Human human = new Human();
human.speak(); // Output - Hello
// 36: invokevirtual #7 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:()V
human.speak("Hindi"); // Output - Namaste
// 42: invokevirtual #9 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:(Ljava/lang/String;)V
Wenn wir uns den obigen Code ansehen, können wir sehen, dass die Bytecodes von humanMammal.speak (), human.speak () und human.speak ("Hindi") völlig unterschiedlich sind, da der Compiler anhand der Argumentliste zwischen ihnen unterscheiden kann und Klassenreferenz. Aus diesem Grund wird Method Overloading als statischer Polymorphismus bezeichnet .
Der Bytecode für anyMammal.speak () und humanMammal.speak () ist jedoch identisch, da laut Compiler beide Methoden für die Mammal-Referenz aufgerufen werden. Die Ausgabe für beide Methodenaufrufe ist jedoch unterschiedlich, da JVM zur Laufzeit weiß, welches Objekt eine Referenz enthält, und JVM aufruft Die Methode für das Objekt und aus diesem Grund wird das Überschreiben von Methoden als dynamischer Polymorphismus bezeichnet.
Aus dem obigen Code und Bytecode geht hervor, dass während der Kompilierungsphase die Aufrufmethode vom Referenztyp berücksichtigt wird. Zur Ausführungszeit wird die Methode jedoch von dem Objekt aufgerufen, das die Referenz enthält.
Wenn Sie mehr darüber erfahren möchten, lesen Sie mehr darüber, wie JVM das Überladen und Überschreiben von Methoden intern handhabt .
Statischer Polymorphismus: Hier wird die Entscheidung, welche Methode ausgeführt werden soll, während der Kompilierungszeit festgelegt. Ein Beispiel hierfür könnte das Überladen von Methoden sein.
Dynamischer Polymorphismus: Hier wird die Entscheidung zur Auswahl der auszuführenden Methode zur Laufzeit festgelegt. Das Überschreiben von Methoden könnte ein Beispiel dafür sein.
Polymorphismus bezieht sich auf die Fähigkeit eines Objekts, sich für denselben Auslöser unterschiedlich zu verhalten.
Statischer Polymorphismus (Polymorphismus zur Kompilierungszeit)
Dynamischer Polymorphismus (Laufzeitpolymorphismus)
Kompilierungszeitpolymorphismus (statische Bindung / frühe Bindung): Wenn wir im statischen Polymorphismus eine Methode in unserem Code aufrufen, wird die Definition dieser Methode tatsächlich nur zur Kompilierungszeit aufgelöst.
(oder)
Zur Kompilierungszeit weiß Java, welche Methode durch Überprüfen der Methodensignaturen aufgerufen werden muss. Dies wird als Polymorphismus zur Kompilierungszeit oder statische Bindung bezeichnet.
Dynamischer Polymorphismus (Late Binding / Runtime Polymorphism): Zur Laufzeit wartet Java bis zur Laufzeit, um festzustellen, auf welches Objekt in der Referenz tatsächlich verwiesen wird. Die Methodenauflösung wurde zur Laufzeit durchgeführt, was wir als Laufzeitpolymorphismus bezeichnen.
Betrachten Sie den folgenden Code:
public class X
{
public void methodA() // Base class method
{
System.out.println ("hello, I'm methodA of class X");
}
}
public class Y extends X
{
public void methodA() // Derived Class method
{
System.out.println ("hello, I'm methodA of class Y");
}
}
public class Z
{
public static void main (String args []) {
//this takes input from the user during runtime
System.out.println("Enter x or y");
Scanner scanner = new Scanner(System.in);
String value= scanner.nextLine();
X obj1 = null;
if(value.equals("x"))
obj1 = new X(); // Reference and object X
else if(value.equals("y"))
obj2 = new Y(); // X reference but Y object
else
System.out.println("Invalid param value");
obj1.methodA();
}
}
Wenn Sie sich nun den Code ansehen, können Sie nie sagen, welche Implementierung von methodA () ausgeführt wird, da dies davon abhängt, welchen Wert der Benutzer zur Laufzeit gibt. Es wird also nur zur Laufzeit entschieden, welche Methode aufgerufen wird. Daher Laufzeitpolymorphismus.
Das Überladen von Methoden ist ein Polymorphismus zur Kompilierungszeit. Nehmen wir ein Beispiel, um das Konzept zu verstehen.
class Person //person.java file
{
public static void main ( String[] args )
{
Eat e = new Eat();
e.eat(noodle); //line 6
}
void eat (Noodles n) //Noodles is a object line 8
{
}
void eat ( Pizza p) //Pizza is a object
{
}
}
In diesem Beispiel hat Person eine Essmethode, die angibt, dass sie entweder Pizza oder Nudeln essen kann. Daß die Methode eat beim Kompilieren dieser Person.java überladen ist, löst der Compiler den Methodenaufruf "e.eat (Nudeln) [in Zeile 6] mit der in Zeile 8 angegebenen Methodendefinition auf. Dies ist die Methode, die Nudeln als Parameter verwendet und der gesamte Prozess wird vom Compiler ausgeführt, so dass es sich um Polymorphismus zur Kompilierungszeit handelt. Der Prozess des Ersetzens des Methodenaufrufs durch die Methodendefinition wird als Bindung bezeichnet. In diesem Fall wird er vom Compiler ausgeführt, sodass er als frühe Bindung bezeichnet wird.
Nach Nareshs Antwort ist dynamischer Polymorphismus in Java nur "dynamisch", da die virtuelle Maschine vorhanden ist und der Code zur Laufzeit interpretiert werden kann und nicht der Code, der nativ ausgeführt wird.
In C ++ muss es zur Kompilierungszeit aufgelöst werden, wenn es offensichtlich mit gcc zu einer nativen Binärdatei kompiliert wird. Der Laufzeitsprung und Thunk in der virtuellen Tabelle wird jedoch weiterhin als "Lookup" oder "Dynamic" bezeichnet. Wenn C B erbt und Sie deklarieren , zeigt c bereits auf das äußere C-Objekt und der Zeiger wird an C :: method1 () im Textsegment übergeben. Siehe: http://www.programmersought.com/article/2572545946/B* b = new C(); b->method1();
, wird b vom Compiler aufgelöst, um auf ein B-Objekt in C zu verweisen (für eine einfache Klasse erbt eine Klassensituation, das B-Objekt in C und C beginnt an derselben Speicheradresse, also nichts muss durchgeführt werden, es wird auf das vptr zeigen, das beide verwenden). Wenn C B und A erbt, hat die virtuelle Funktionstabelle des A-Objekts im C-Eintrag für Methode1 einen Thunk, der den Zeiger auf den Anfang des einkapselnden C-Objekts versetzt und ihn dann an die reale A :: -Methode1 () übergibt. in dem Textsegment, das C überschrieben hat. ZumC* c = new C(); c->method1()
In Java kann B b = new C(); b.method1();
die virtuelle Maschine den Typ des mit b gepaarten Objekts dynamisch überprüfen, den richtigen Zeiger übergeben und die richtige Methode aufrufen. Der zusätzliche Schritt der virtuellen Maschine macht virtuelle Funktionstabellen oder den Typ, der zur Kompilierungszeit aufgelöst wird, überflüssig, selbst wenn er zur Kompilierungszeit bekannt sein könnte. Es ist nur eine andere Methode, die sinnvoll ist, wenn eine virtuelle Maschine beteiligt ist und Code nur zu Bytecode kompiliert wird.