Jaka jest różnica między dynamicznym a statycznym polimorfizmem w Javie?


118

Czy ktoś może podać prosty przykład wyjaśniający różnicę między dynamicznym a statycznym polimorfizmem w Javie?


4
Zastąpienia są czasami określane jako „statyczny polimorfizm”. To trochę rozciąga, ale tak właśnie się dzieje.
dasblinkenlight

@dasblinkenlight dzięki za informację. czy jest na to jakiś przykład?
Prabhakar Manthena

Wyszukaj „przeciążanie metody” i „przesłanianie metody”.
dasblinkenlight

5
Nie rozumiem, jak przeciążenie jest polimorfizmem. Polimorfizm to pojęcie przedmiotu. powinniśmy być w stanie pokazać obiekt B jako obiekt A. z dołu (odpowiedz) przykład pokazujesz psa jako zwierzę i stąd jest to polimorfizm. Ale w przypadku przeciążania wywołujesz inną metodę, ale z „tą samą nazwą”. Jak to może być polimorfizm. Stąd „wiązanie statyczne” jest właściwym terminem do użycia, ale statyczny polimorfizm nie występuje w przypadku przeciążenia.
Punith Raj

@PunithRaj Prawdopodobnie odnosisz się do polimorfizmu podtypów . Istnieje inny rodzaj, zwany Ad hoc, który dotyczy przeciążenia.
Kelvin

Odpowiedzi:


196

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)

przykład przeciążenia:

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 
  }  
}  

nadrzędny przykład:

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
   }
}

6
Jestem nowy w Javie, więc tylko ciekawostki, jaka jest podstawowa koncepcja pomiędzy Animal reference but Dog object, dlaczego nie możemy użyć Dog reference and dog object?
pratyay

3
W powyższym przykładzie starałem się pokazać pojęcie polimorfizmu. możemy stworzyć referencję i obiekt tej samej klasy, ale nie możemy nadpisać metody. proszę przeczytać poniższy post: stackoverflow.com/questions/12159601/…
KhAn SaAb

Przeciążanie metody to polimorfizm czasu kompilacji. jest w ten sam sposób. czy przeciążanie konstruktora jest również polimorfizmem czasu kompilacji?
Gaali Prabhakar

29
  • 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


17

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).


2
Ta odpowiedź pełna błędów: (1) Przeciążenie metody nie jest dynamicznym polimorfizmem. To statyczny polimorfizm. (2) Metody statyczne nigdy nie są nadpisywane, są ukrywane / zasłaniane. (3) Metody prywatne nie są „zastępowane”. Przede wszystkim nigdy nie są dziedziczone.
John Red

15

Powiązanie odnosi się do połączenia między wywołaniem metody a definicją metody.

Ten rysunek wyraźnie pokazuje, co jest wiążące.

wiążący

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.

wprowadź opis obrazu tutaj

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.

wprowadź opis obrazu tutaj

Odwołanie do statycznego wiązania i dynamicznego wiązania w języku Java


lepiej niż przedtem.
AnBisw

8

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


8

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ę).


* (obiekt jest tworzony w czasie wykonywania i trafia na stertę), powinien działać w czasie
Meet

7

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ę.
prime

1
Dynamiczne wiązanie i nadpisywanie jest uderzającym punktem dla polimorfizmu
Ravindra babu

5

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 Mammali Humanklasę

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 .


3

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.


3

Polimorfizm odnosi się do zdolności obiektu do zachowania się inaczej dla tego samego wyzwalacza.

Statyczny polimorfizm (polimorfizm w czasie kompilacji)

  • Static Polimorphism decyduje, którą metodę wykonać w czasie kompilacji.
  • Przeciążenie metody jest przykładem statycznego polimorfizmu i wymagane jest, aby zachodził statyczny polimorfizm.
  • Statyczny polimorfizm osiągnięty poprzez statyczne wiązanie.
  • Statyczny polimorfizm występuje w tej samej klasie.
  • Przypisanie obiektu nie jest wymagane w przypadku statycznego polimorfizmu.
  • Dziedziczenie nie dotyczy polimorfizmu statycznego.

Dynamiczny polimorfizm (polimorfizm w czasie wykonywania)

  • Dynamiczny polimorfizm decyduje, którą metodę wykonać w czasie wykonywania.
  • Zastępowanie metody jest przykładem dynamicznego polimorfizmu i wymagane jest, aby zachodził dynamiczny polimorfizm.
  • Dynamiczny polimorfizm osiągnięty dzięki dynamicznemu wiązaniu.
  • Dynamiczny polimorfizm zachodzi między różnymi klasami.
  • Jest to wymagane, gdy obiekt podklasy jest przypisany do obiektu superklasy w celu uzyskania dynamicznego polimorfizmu.
  • Dziedziczenie związane z dynamicznym polimorfizmem.

1

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.


1

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.


0

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.


0

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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.