Czy ktoś może podać prosty przykład wyjaśniający różnicę między dynamicznym a statycznym polimorfizmem w Javie?
Czy ktoś może podać prosty przykład wyjaśniający różnicę między dynamicznym a statycznym polimorfizmem w Javie?
Odpowiedzi:
Wielopostaciowość
1. Statyczne wiązanie / Powiązanie w czasie kompilacji / Wczesne wiązanie / Przeciążenie metod. (W tej samej klasie)
2. Dynamiczne wiązanie / wiązanie w czasie wykonywania / późne wiązanie / zastępowanie metod. (W różnych klasach)
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
, dlaczego nie możemy użyć Dog reference and dog object
?
Przykładem statycznego polimorfizmu byłoby przeciążenie metody
podczas gdy nadpisywanie byłoby przykładem dynamicznego polimorfizmu.
Ponieważ w przypadku przeciążenia, w czasie kompilacji kompilator wie, którą metodę połączyć z wywołaniem. Jednak jest on określany w czasie wykonywania dla dynamicznego polimorfizmu
Polimorfizm dynamiczny (w czasie wykonywania) to polimorfizm występujący w czasie wykonywania. W tym przypadku kompilator Java nie rozumie, która metoda jest wywoływana w czasie kompilacji. Tylko JVM decyduje, która metoda jest wywoływana w czasie wykonywania. Przeciążanie metod i nadpisywanie metod przy użyciu metod instancji to przykłady dynamicznego polimorfizmu.
Na przykład,
Rozważ aplikację, która serializuje i deserializuje różne typy dokumentów.
Możemy mieć „Dokument” jako klasę bazową i różne klasy typów dokumentów z niego wywodzących się. Np. XMLDocument, WordDocument itp.
Klasa dokumentu definiuje metody „Serialize ()” i „De-serialize ()” jako wirtualne, a każda klasa pochodna zaimplementuje te metody na swój własny sposób w oparciu o rzeczywistą zawartość dokumentów.
W przypadku konieczności serializacji / deserializacji różnych typów dokumentów obiekty dokumentu będą odwoływane przez odwołanie do klasy (lub wskaźnik) oraz w przypadku wywołania metody „Serialize ()” lub „De-serialize ()” na nim wywoływane są odpowiednie wersje metod wirtualnych.
Polimorfizm statyczny (czas kompilacji) to polimorfizm wykazany w czasie kompilacji. Tutaj kompilator Java wie, która metoda jest wywoływana. Przeciążanie metod i nadpisywanie metod przy użyciu metod statycznych; przesłanianie metody przy użyciu metod prywatnych lub końcowych są przykładami polimorfizmu statycznego
Na przykład,
Obiekt pracownika może mieć dwie metody print (), z których jedna nie pobiera argumentów, a druga pobiera przedrostek, który ma być wyświetlany wraz z danymi pracownika.
Biorąc pod uwagę te interfejsy, gdy wywoływana jest metoda print () bez żadnych argumentów, kompilator patrząc na argumenty funkcji wie, która funkcja ma zostać wywołana i odpowiednio generuje kod wynikowy.
Aby uzyskać więcej informacji, przeczytaj „Co to jest polimorfizm” (Google it).
Powiązanie odnosi się do połączenia między wywołaniem metody a definicją metody.
Ten rysunek wyraźnie pokazuje, co jest wiążące.
Na tym obrazku wywołanie „a1.methodOne ()” wiąże się z odpowiednią definicją methodOne (), a wywołanie „a1.methodTwo ()” jest powiązane z odpowiednią definicją methodTwo ().
Dla każdego wywołania metody powinna istnieć odpowiednia definicja metody. To jest reguła w java. Jeśli kompilator nie widzi właściwej definicji metody dla każdego wywołania metody, zgłasza błąd.
Teraz przejdź do wiązania statycznego i dynamicznego w java.
Statyczne wiązanie w Javie:
Wiązanie statyczne to powiązanie, które ma miejsce podczas kompilacji. Nazywa się to również wczesnym wiązaniem, ponieważ wiązanie ma miejsce przed faktycznym uruchomieniem programu
.
Wiązanie statyczne można zademonstrować jak na poniższym obrazku.
Na tym rysunku „a1” jest zmienną referencyjną typu klasy A wskazującą na obiekt klasy A. „a2” jest również zmienną referencyjną typu klasy A, ale wskazuje na obiekt klasy B.
Podczas kompilacji, podczas wiązania, kompilator nie sprawdza typu obiektu, na który wskazuje określona zmienna referencyjna. Po prostu sprawdza typ zmiennej referencyjnej, przez którą wywoływana jest metoda i sprawdza, czy istnieje dla niej definicja metody w tym typie.
Na przykład dla wywołania metody „a1.method ()” na powyższym obrazku kompilator sprawdza, czy istnieje definicja metody dla metody method () w klasie A. Ponieważ „a1” jest typem klasy A. Podobnie, dla wywołania metody „a2.method ()” sprawdza, czy istnieje definicja metody dla method () w klasie A. Ponieważ „a2” jest również typem klasy A. Nie sprawdza, na który obiekt wskazuje „a1” i „a2”. Ten typ wiązania nazywany jest wiązaniem statycznym.
Dynamiczne wiązanie w Javie:
Dynamiczne wiązanie to powiązanie, które ma miejsce w czasie wykonywania. Nazywa się to również późnym wiązaniem, ponieważ wiązanie ma miejsce, gdy program faktycznie działa.
W czasie wykonywania do powiązania używane są rzeczywiste obiekty. Na przykład dla wywołania „a1.method ()” na powyższym obrazku zostanie wywołana metoda () rzeczywistego obiektu, na który wskazuje „a1”. Dla wywołania „a2.method ()” zostanie wywołana metoda () rzeczywistego obiektu, na który wskazuje „a2”. Ten typ wiązania nazywa się wiązaniem dynamicznym.
Dynamiczne wiązanie z powyższego przykładu można zademonstrować jak poniżej.
Odwołanie do statycznego wiązania i dynamicznego wiązania w języku Java
Polimorfizm: Polimorfizm to zdolność obiektu do przyjmowania wielu form. Najbardziej powszechne użycie polimorfizmu w OOP występuje, gdy odwołanie do klasy nadrzędnej jest używane w odniesieniu do obiektu klasy potomnej.
Dynamiczne wiązanie / polimorfizm w czasie wykonywania:
Polimorfizm w czasie wykonywania, znany również jako przesłanianie metody. W tym mechanizmie, za pomocą którego wywołanie nadpisanej funkcji jest rozwiązywane w czasie wykonywania.
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");
}
}
Wynik:
Metoda startu wewnętrznego Car
Wiązanie statyczne / polimorfizm w czasie kompilacji:
O wyborze metody decyduje się tylko w czasie kompilacji.
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;
}
}
Dane wyjściowe: metoda sortowania kolekcji Inside
przeciążenie metody jest przykładem czasu kompilacji / statycznego polimorfizmu, ponieważ wiązanie metody między wywołaniem metody a definicją metody ma miejsce w czasie kompilacji i zależy od referencji klasy (referencja utworzona w czasie kompilacji i trafia na stos).
przesłanianie metody jest przykładem wykonywania / dynamicznego polimorfizmu, ponieważ wiązanie metody między wywołaniem metody a definicją metody ma miejsce w czasie wykonywania i zależy od obiektu klasy (obiekt utworzony w czasie wykonywania i trafia na stertę).
W prostych słowach :
Polimorfizm statyczny : ta sama nazwa metody jest przeciążona innym typem lub liczbą parametrów w tej samej klasie (inny podpis). Wywołanie metody docelowej jest rozwiązywane w czasie kompilacji.
Dynamiczny polimorfizm : ta sama metoda jest zastępowana tym samym podpisem w różnych klasach . Typ obiektu, dla którego wywoływana jest metoda, nie jest znany w czasie kompilacji, ale zostanie określony w czasie wykonywania.
Generalnie przeciążenie nie będzie uważane za polimorfizm.
Ze strony samouczka Java :
Podklasy klasy mogą definiować własne unikalne zachowania, a mimo to współdzielić niektóre funkcje klasy nadrzędnej
Generally overloading won't be considered as polymorphism.
czy możesz rozwinąć tę kwestię.
Przeciążanie metod jest znane jako statyczny polimorfizm, a także znane jako polimorfizm czasu kompilacji lub statyczne wiązanie, ponieważ przeciążone wywołania metod są rozwiązywane w czasie kompilacji przez kompilator na podstawie listy argumentów i odwołania, w którym wywołujemy metodę.
I Metoda Zastępowanie znany jest jako dynamiczna polimorfizmu lub prostego polimorfizmu lub Method Runtime Dispatch czy dynamiczne wiązanie ponieważ przesłonięte wywołanie metody zostanie rozwiązany przy starcie.
Aby zrozumieć, dlaczego tak jest, weźmy przykład Mammal
i Human
klasę
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");
}
}
W poniższych wierszach kodu zawarłem dane wyjściowe oraz kod bajtowy
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
Patrząc na powyższy kod, widzimy, że kody bajtowe humanMammal.speak (), human.speak () i human.speak („hindi”) są zupełnie inne, ponieważ kompilator jest w stanie je rozróżnić na podstawie listy argumentów i odniesienie do klasy. I właśnie dlatego przeciążanie metod jest znane jako statyczny polimorfizm .
Ale kod bajtowy dla anyMammal.speak () i humanMammal.speak () jest taki sam, ponieważ zgodnie z kompilatorem obie metody są wywoływane w odwołaniu do klasy Mammal, ale dane wyjściowe dla obu wywołań metod są różne, ponieważ w czasie wykonywania JVM wie, jaki obiekt przechowuje odwołanie i wywołuje JVM metoda na obiekcie i dlatego przesłanianie metody jest znane jako dynamiczny polimorfizm.
Tak więc z powyższego kodu i kodu bajtowego jasno wynika, że podczas fazy kompilacji metoda wywołania jest rozważana z typu referencyjnego. Ale w czasie wykonywania metoda zostanie wywołana z obiektu, do którego odwołuje się odwołanie.
Jeśli chcesz dowiedzieć się więcej na ten temat, możesz przeczytać więcej na temat tego, jak JVM obsługuje wewnętrzne przeciążanie i zastępowanie metod .
Static Polimorphism: to sytuacja, w której decyzja o rozwiązaniu metody do wykonania jest określana w czasie kompilacji. Przykładem może być przeciążanie metod.
Dynamiczny polimorfizm: to sytuacja, w której decyzja o wyborze metody do wykonania jest podejmowana w czasie wykonywania. Przykładem może być przesłanianie metody.
Polimorfizm odnosi się do zdolności obiektu do zachowania się inaczej dla tego samego wyzwalacza.
Statyczny polimorfizm (polimorfizm w czasie kompilacji)
Dynamiczny polimorfizm (polimorfizm w czasie wykonywania)
Polimorfizm w czasie kompilacji (wiązanie statyczne / wczesne wiązanie): W polimorfizmie statycznym, jeśli wywołasz metodę w naszym kodzie, wówczas definicja tej metody zostanie wywołana w rzeczywistości tylko w czasie kompilacji.
(lub)
W czasie kompilacji Java wie, którą metodę wywołać, sprawdzając podpisy metod. Nazywa się to więc polimorfizmem w czasie kompilacji lub wiązaniem statycznym.
Dynamiczny polimorfizm (późne wiązanie / polimorfizm w czasie wykonywania): W czasie wykonywania Java czeka do czasu wykonania, aby określić, który obiekt jest faktycznie wskazywany przez odwołanie. Rozwiązanie metody zostało podjęte w czasie wykonywania, dlatego nazywamy go polimorfizmem w czasie wykonywania.
Rozważ poniższy kod:
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();
}
}
Teraz, patrząc na kod, nigdy nie można powiedzieć, która implementacja methodA () zostanie wykonana, ponieważ zależy to od tego, jaką wartość poda użytkownik w czasie wykonywania. Tak więc tylko w czasie wykonywania jest podejmowane decyzje, która metoda zostanie wywołana. Stąd polimorfizm Runtime.
Przeciążanie metod to polimorfizm czasu kompilacji, weźmy przykład, aby zrozumieć koncepcję.
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
{
}
}
W tym przykładzie Osoba ma metodę jedzenia, która oznacza, że może zjeść pizzę lub makaron. Że metoda eat jest przeciążona kiedy kompilujemy ten Person.java kompilator rozwiązuje wywołanie metody "e.eat (noodles) [które znajduje się w linii 6] z definicją metody określoną w linii 8 czyli jest to metoda, która przyjmuje makaron jako parametr a cały proces jest wykonywany przez kompilator, więc jest to polimorfizm czasu kompilacji.Proces zamiany wywołania metody na definicję metody jest nazywany wiązaniem, w tym przypadku jest wykonywany przez kompilator, więc jest nazywany wczesnym wiązaniem.
Kontynuując odpowiedź Naresha, dynamiczny polimorfizm jest „dynamiczny” w Javie tylko ze względu na obecność maszyny wirtualnej i jej zdolność do interpretowania kodu w czasie wykonywania, a nie kodu działającego natywnie.
W C ++ musi być rozwiązany w czasie kompilacji, jeśli jest kompilowany do natywnego pliku binarnego przy użyciu gcc, oczywiście; jednak skok i skok w czasie wykonywania w tabeli wirtualnej są nadal określane jako „wyszukiwanie” lub „dynamiczne”. Jeśli C dziedziczy B, a ty zadeklarujesz B* b = new C(); b->method1();
, b zostanie rozwiązane przez kompilator w celu wskazania obiektu B wewnątrz C (dla prostej klasy dziedzicza sytuację klasową, obiekt B w C i C rozpocznie się od tego samego adresu pamięci, więc nic jest wymagane; będzie wskazywać na vptr, którego używają oboje). Jeśli C dziedziczy B i A, tablica funkcji wirtualnych obiektu A wewnątrz wpisu C dla metody method1 będzie miała wartość, która przesunie wskaźnik do początku enkapsulującego obiektu C, a następnie przekaże go do rzeczywistej A :: method1 () w segmencie tekstu, który zastąpił C. DlaC* c = new C(); c->method1()
, c będzie już wskazywać na zewnętrzny obiekt C, a wskaźnik zostanie przekazany do C :: metoda1 () w segmencie tekstowym. Zobacz: http://www.programmersought.com/article/2572545946/
W Javie B b = new C(); b.method1();
maszyna wirtualna może dynamicznie sprawdzać typ obiektu sparowanego z b oraz może przekazać poprawny wskaźnik i wywołać poprawną metodę. Dodatkowy krok maszyny wirtualnej eliminuje potrzebę tabel funkcji wirtualnych lub typu rozwiązywanego w czasie kompilacji, nawet jeśli może być znany w czasie kompilacji. Jest to po prostu inny sposób, który ma sens, gdy w grę wchodzi maszyna wirtualna, a kod jest kompilowany tylko do kodu bajtowego.