Jaka jest główna różnica między dziedziczeniem a polimorfizmem?

172

Zadano mi to pytanie na zakończenie dzisiejszego egzaminu z otwartej książki i zgubiłem się. Czytałem Head first Javai obie definicje wydawały się być dokładnie takie same. Zastanawiałem się tylko, jaka jest GŁÓWNA różnica w moim własnym umyśle. Wiem, że istnieje wiele podobnych pytań, ale nie widziałem żadnego, które zapewnia ostateczną odpowiedź.

Darren Burgess
źródło
2
W jakiś sposób związane z tym pytaniem: Czy polimorfizm jest możliwy bez dziedziczenia
Edwin Dalorzo

Odpowiedzi:

289

Dziedziczenie ma miejsce, gdy „klasa” pochodzi od istniejącej „klasy”. Więc jeśli masz Personklasę, to masz Studentklasę, która się rozszerza Person, Student dziedziczy wszystko, co Personma. Istnieje kilka szczegółów dotyczących modyfikatorów dostępu, które umieszczasz w polach / metodach w Person, ale to jest podstawowa idea. Na przykład, jeśli masz włączone pole prywatne Person, Studentnie zobaczy go, ponieważ jego pola prywatne i prywatne nie są widoczne dla podklas.

Polimorfizm dotyczy tego, w jaki sposób program decyduje, jakich metod powinien używać, w zależności od tego, jaki typ rzeczy ma. Jeśli masz a Person, który ma readmetodę i masz Studentrozszerzenie Person, które ma własną implementację read, to, która metoda zostanie wywołana, jest określana przez środowisko wykonawcze, w zależności od tego, czy masz Personplik Student. To trochę skomplikowane, ale jeśli zrobisz coś takiego

Person p = new Student();
p.read();

wywoływana jest metoda odczytu Studenta . Taki jest polimorfizm w akcji. Możesz wykonać to zadanie, ponieważ a Student to a Person , ale środowisko wykonawcze jest wystarczająco inteligentne, aby wiedzieć, że rzeczywisty typ pto Student .

Pamiętaj, że szczegóły różnią się w zależności od języka. Możesz na przykład dziedziczyć w javascript, ale jest to zupełnie inne niż sposób, w jaki działa w Javie.

hvgotcodes
źródło
9
@ hvgtcodes czyli w pigułce relacja nadklasa-podklasa to dziedziczenie, a koncepcja implementacji tej samej metody w inny sposób między klasą nadrzędną a jej podklasami i wywoływanie ich na podstawie sytuacji to Polimorfizm. Mam rację?
Muhammad Raihan Muhaimin
1
@hvgotcodes jednak powiedzieć, czy Person„s readmetoda wykorzystuje modyfikator dostępu publicznego, nie będzie Studentobiektów móc do nich dostęp? i Student s = new Student();czy nie będzie to łatwiejsze? Nadal nie do końca odczuwam korzyści płynące z polimorfizmu.
Scorpiorian83
1
@hvgotcodes Student s = new Student () będzie działać. Ale powiedzmy, że po napisaniu dużej części kodu za pomocą tego pomysłu, a później zdajesz sobie sprawę, że popełniłeś błąd. Ta osoba w rzeczywistości nie jest uczniem, jest nauczycielem. Możesz więc po prostu zmienić z Person p = new Student () na Person p = new Teacher (), wtedy znacznie ułatwi ci to życie.
munmunbb
Moje pytanie tutaj, dlaczego chcesz użyć Person p = new Student();zamiast Student p = new Student();?
PerfectContrast
@PerfectContrast Myślę, że jest to przydatne, gdy chcesz mieć ucznia, kierowcę, nauczyciela itp. Jako osobę i grupujesz ich na liście lub coś w tym stylu. Więc kiedy wywołujesz „czytaj” dla wszystkich, każdy wywołuje własną metodę „czytaj”.
savante
205

Dziedziczenie odnosi się do wykorzystania struktury i zachowania superklasy w podklasie.

Polimorfizm odnosi się do zmiany zachowania superklasy w podklasie.

Ted Hopp
źródło
5
Czy ta odpowiedź sugeruje, że polimorfizm wymaga dziedziczenia?
jaco0646
6
@ jaco0646 - Myślę, że w kontekście Java. (W innych językach, może nie tak bardzo). Zwróć uwagę, że „super klasa” i „podklasa” są tutaj używane luźno. Polimorfizm może również oznaczać dziedziczenie zachowania określonego (ale nie zaimplementowanego) w interfejsie.
Ted Hopp,
1
@AlirezaRahmani - nie rozumiem twojego komentarza. Czy masz na myśli, że dziedziczenie nie obejmuje dziedziczenia zarówno właściwości, jak i zachowania? Byłoby to sprzeczne z tym, jak Java (i większość opartych na klasach języków obiektowych) definiuje dziedziczenie. Ze specyfikacji języka Java, §8.4.8 : „Klasa C dziedziczy ze swojej bezpośredniej nadklasy wszystkie konkretne metody m(zarówno statici instance) z nadklasy, dla której ...” (a następnie szczegóły dotyczące dziedziczenia). Dla mnie brzmi to jak „ponowne wykorzystanie kodu”.
Ted Hopp
@TedHopp Inheritance jest przede wszystkim narzędziem polimorficznym, ale niektórzy ludzie, ku późniejszemu zagrożeniu, próbują go używać jako sposobu ponownego wykorzystania / udostępniania kodu. Uzasadnieniem jest to, że „dobrze, jeśli odziedziczę, otrzymam wszystkie metody za darmo”, ale pomijając fakt, że te dwie klasy potencjalnie nie mają związku polimorficznego.
Alireza Rahmani Khalili
1
@AlirezaRahmani - W Javie (o co pytał OP, zgodnie z tagami), dziedziczenie klas z całą pewnością obejmuje dziedziczenie zachowania. To część definicji języka. Fakt, że może to być nadużywane, jak opisujesz, jest jedną ze słabości Javy. (Powiązana słabość polegała na deklarowaniu klas w celu implementacji interfejsów po prostu w celu zaimportowania stałych zdefiniowanych w interfejsie. Ostatecznie projektanci Javy wprowadzili rozwiązanie, import staticaby wyeliminować to niewłaściwe użycie interfejsów). W przypadku czystego polimorfizmu w Javie narzędziem, które należy zastosować, są interfejsy, a nie dziedziczenie klas.
Ted Hopp
63

Polimorfizm : zdolność do traktowania obiektów różnych typów w podobny sposób. Przykład: Żyrafa i Krokodyl to zarówno Zwierzęta, jak i zwierzęta mogą Move. Jeśli masz instancję Animal, możesz zadzwonić, Movenie wiedząc ani nie dbając o typ zwierzęcia.

Dziedziczenie : jest to jeden ze sposobów jednoczesnego osiągnięcia polimorfizmu i ponownego wykorzystania kodu.

Inne formy polimorfizmu : istnieją inne sposoby osiągnięcia polimorfizmu, takie jak interfejsy, które zapewniają tylko polimorfizm, ale nie pozwalają na ponowne wykorzystanie kodu (czasami kod jest zupełnie inny, na przykład Movedla Węża byłby zupełnie inny niż Movedla psa, w takim przypadku Interfejs byłby lepszym wyborem polimorficznym w tym przypadku.

W innych dynamicznych językach polimorfizm można osiągnąć za pomocą Duck Typing, co oznacza, że ​​klasy nie muszą nawet dzielić tej samej klasy bazowej lub interfejsu, potrzebują jedynie metody o tej samej nazwie. Lub nawet bardziej dynamiczny, jak Javascript, w ogóle nie potrzebujesz klas, tylko obiekt o tej samej nazwie metody może być używany polimorficznie.

Davy8
źródło
17

Główną różnicą jest to, że polimorfizm jest specyficznym wynikiem dziedziczenia. Polimorfizm polega na określeniu metody, która ma zostać wywołana, w czasie wykonywania na podstawie typu obiektu. Jest to sytuacja, która pojawia się, gdy jedna klasa dziedziczy po innej i przesłania określoną metodę. Jednak w normalnym drzewie dziedziczenia nie trzeba przesłonić żadnych metod, a zatem nie wszystkie wywołania metod muszą być polimorficzne. Czy to ma sens? Jest to podobny problem do wszystkich samochodów Forda, ale nie wszystkie samochody są Fordami (chociaż nie do końca…).

Ponadto polimorfizm zajmuje się wywołaniem metod, podczas gdy dziedziczenie opisuje również elementy składowe danych itp.

Chris Thompson
źródło
12

W Javie są one ściśle powiązane. Dzieje się tak, ponieważ Java używa techniki wywoływania metody zwanej „dynamicznym wysyłaniem”. Jeżeli mam

public class A {
  public void draw() { ... }
  public void spin() { ... }
}

public class B extends A {
  public void draw() { ... }
  public void bad() { ... }
}

...

A testObject = new B();

testObject.draw(); // calls B's draw, polymorphic
testObject.spin(); // calls A's spin, inherited by B
testObject.bad(); // compiler error, you are manipulating this as an A

Następnie widzimy, która dziedziczy B spinz A. Jednak, gdy staramy się manipulować obiektu, jak gdyby był to typ A, my wciąż za zachowanie b draw. drawZachowanie jest polimorficzny.

W niektórych językach polimorfizm i dziedziczenie nie są tak blisko spokrewnione. Na przykład w C ++ funkcje, które nie zostały zadeklarowane jako wirtualne, są dziedziczone, ale nie będą wysyłane dynamicznie, więc nie uzyskasz tego polimorficznego zachowania, nawet jeśli używasz dziedziczenia.

W javascript każde wywołanie funkcji jest dynamicznie wysyłane, a Ty masz problemy z pisaniem. Oznacza to, że możesz mieć kilka niepowiązanych obiektów, każdy z własnymi draw, mieć funkcję iterującą po nich i wywołującą funkcję, a każdy z nich będzie się dobrze zachowywał. Miałbyś swój własny losowanie polimorficzne bez potrzeby dziedziczenia.

ccoakley
źródło
12

Polimorfizm: załóżmy, że pracujesz dla firmy sprzedającej długopisy. Tworzysz więc bardzo fajną klasę o nazwie „Pióro”, która zawiera wszystko, co musisz wiedzieć o piórze. Piszesz różnego rodzaju zajęcia dotyczące fakturowania, wysyłki, tworzenia faktur, wszystko przy użyciu klasy Pen. Przychodzi jeden z szefów i mówi: „Wspaniała wiadomość! Firma się rozwija i teraz sprzedajemy książki i płyty CD!” Nie jest to świetna wiadomość, ponieważ teraz musisz zmienić wszystkie klasy, które używają pióra, aby również używały książki i płyty CD. Ale co by było, gdybyś pierwotnie utworzył interfejs o nazwie „Produkt do sprzedaży”, a Pen zaimplementował ten interfejs. Wtedy mógłbyś napisać wszystkie klasy wysyłki, fakturowania itp., Aby używać tego interfejsu zamiast pióra. Teraz wszystko, co musisz zrobić, to utworzyć nową klasę o nazwie Book & CompactDisc, która implementuje interfejs SellableProduct. Z powodu polimorfizmu wszystkie inne klasy mogły nadal działać bez zmian! Ma sens?

Oznacza to więc użycie dziedziczenia, które jest jednym ze sposobów osiągnięcia polimorfizmu.

Polimoryzm może być możliwy w klasie / interfejsie, ale dziedziczenie zawsze między 2 LUB więcej klasami / interfejsami. Dziedziczenie zawsze jest zgodne z relacją „jest-a”, podczas gdy nie zawsze jest zgodne z polimorfizmem (który może być zgodny zarówno z relacją „jest-a” / „ma-a”.

AmitK
źródło
6

Dziedziczenie jest bardziej statyczne (jedna klasa rozszerza inną), podczas gdy polimorfizm jest dynamiczny / działający (obiekt zachowuje się zgodnie ze swoim typem dynamicznym / uruchomieniowym, a nie statycznym / deklaracyjnym).

Na przykład

// This assignment is possible because B extends A
A a = new B();
// polymorphic call/ access
a.foo();

-> Chociaż typ statyczny / deklaracji a to A, rzeczywisty typ dynamiczny / wykonawczy to B, a zatem a.foo () wykona foo zgodnie z definicją w B, a nie w A.

Kolor brązowofioletowy
źródło
3

Polimorfizm to podejście do wyrażania wspólnego zachowania między typami obiektów, które mają podobne cechy. Pozwala także na tworzenie odmian tych cech poprzez nadpisywanie. Dziedziczenie to sposób na osiągnięcie polimorfizmu poprzez hierarchię obiektów, w której obiekty wyrażają relacje i abstrakcyjne zachowania. Nie jest to jednak jedyny sposób na osiągnięcie polimorfizmu. Prototyp to inny sposób wyrażania polimorfizmu, który różni się od dziedziczenia. JavaScript jest przykładem języka używającego prototypu. Wyobrażam sobie, że są też inne sposoby.

laz
źródło
3

Dziedziczenie to pojęcie związane z ponownym wykorzystaniem kodu. Na przykład, jeśli mam klasę nadrzędną, powiedz Animali zawiera pewne atrybuty i metody (w tym przykładzie powiedz makeNoise()i sleep()) i utworzę dwie klasy potomne o nazwie Dogi Cat. Ponieważ zarówno psy, jak i koty zasypiają w ten sam sposób (zakładałbym), nie ma potrzeby dodawania większej funkcjonalności do sleep()metody w podklasach Dogi Catzapewnianych przez klasę nadrzędną Animal. Jednak Dogszczeka i Catmiauczy, więc chociażAnimal klasa mogą mieć metodę na robienie hałasu, pies i kot wydają różne odgłosy w stosunku do siebie nawzajem i innych zwierząt. W związku z tym istnieje potrzeba ponownego zdefiniowania tego zachowania pod kątem określonych typów. Stąd definicja polimorfizmu. Mam nadzieję że to pomoże.

avenger12
źródło
3

Dokumentacja Oracle precyzyjnie podawała różnicę.

dziedziczenie: klasa dziedziczy pola i metody ze wszystkich swoich nadklas, zarówno bezpośrednich, jak i pośrednich. Podklasa może przesłonić metody, które dziedziczy, lub może ukryć pola lub metody, które dziedziczy . (Należy pamiętać, że ukrywanie pól jest ogólnie złą praktyką programistyczną).

polimorfizm: polimorfizm odnosi się do zasady biologii, w której organizm lub gatunek może mieć wiele różnych form lub stadiów. Zasadę tę można również zastosować do programowania obiektowego i języków, takich jak język Java. Podklasy klasy mogą definiować własne unikalne zachowania, a mimo to współdzielić niektóre funkcje klasy nadrzędnej.

wielopostaciowość nie ma zastosowania do pól.

Powiązany post:

Polimorfizm a zastępowanie a przeciążanie

Ravindra babu
źródło
1

Polimorfizm jest efektem dziedziczenia . Może się to zdarzyć tylko w klasach, które się rozszerzają. Pozwala na wywołanie metod klasy bez znajomości dokładnego typu tej klasy. Ponadto polimorfizm występuje w czasie wykonywania .

Na przykład polimorfizm w Javie:

wprowadź opis obrazu tutaj

Dziedziczenie umożliwia klasom pochodnym współużytkowanie interfejsów i kodu ich klas bazowych. Dzieje się to w czasie kompilacji .

Na przykład wszystkie klasy na platformie Java są potomkami obiektu (zdjęcie dzięki uprzejmości firmy Oracle):

wprowadź opis obrazu tutaj

Aby dowiedzieć się więcej o dziedziczeniu i polimorfizmie języka Java

Jasio
źródło
0

Dziedziczenie ma miejsce, gdy klasa A dziedziczy wszystkie niestatyczne chronione / publiczne metody / pola od wszystkich swoich rodziców do Object.

Cosmin Cosmin
źródło
0

Jeśli używasz JAVA, jest to takie proste:

Polimorfizm wykorzystuje metody dziedziczone, ale „nadpisywanie” ich w celu zrobienia czegoś innego (lub tego samego, jeśli nazwiesz super, więc technicznie rzecz biorąc, nie byłoby polimorficzne).

Popraw mnie, jeśli się mylę.

Oliver Dixon
źródło
0

Główny cel polimorfizmu : stworzenie zmiennej referencyjnej do superklasy i trzymanie obiektu podklasy => obiekt może wykonywać wiele zachowań .

W dziedziczenia , podklasa dziedziczy właściwości super klasy .

satya
źródło
0

dziedziczenie jest rodzajem polimorfizmu. Dokładnie w rzeczywistości dziedziczenie jest polimorfizmem dynamicznym. Tak więc po usunięciu dziedziczenia nie można już nadpisać.

Alireza Rahmani Khalili
źródło
0

W przypadku dziedziczenia implementacja jest definiowana w nadklasie - więc zachowanie jest dziedziczone.

class Animal
{
  double location;
  void move(double newLocation)
  {
    location = newLocation;
  }
}

class Dog extends Animal;

W przypadku polimorfizmu implementacja jest definiowana w podklasie - więc dziedziczony jest tylko interfejs .

interface Animal
{
  void move(double newLocation);
}

class Dog implements Animal
{
  double location;
  void move(double newLocation)
  {
    location = newLocation;
  }
}
mherzl
źródło
0

Polimorfizm osiąga się przez dziedziczenie w Java.

├── Animal
└── (instances)
    ├── Cat
    ├── Hamster
    ├── Lion
    └── Moose

├── interface-for-diet
   ├── Carnivore
   └── Herbivore
├── interface-for-habitat
   ├── Pet
   └── Wild

public class Animal {
    void breath() {
    };
}

public interface Carnivore {
    void loveMeat();
}

public interface Herbivore {
    void loveGreens();
}

public interface Pet {
    void liveInside();
}

public interface Wild {
    void liveOutside();
}

public class Hamster extends Animal implements Herbivore, Pet {

    @Override
    public void liveInside() {
        System.out.println("I live in a cage and my neighbor is a Gerbil");
    }

    @Override
    public void loveGreens() {
        System.out.println("I eat Carrots, Grapes, Tomatoes, and More");
    }
}

public class Cat extends Animal implements Carnivore, Pet {
    @Override
    public void liveInside() {
        System.out.println("I live in a cage and my neighbr is a Gerbil");
    }

    @Override
    public void loveMeat() {
        System.out.println("I eat Tuna, Chicken, and More");
    }
}

public class Moose extends Animal implements Herbivore, Wild {

    @Override
    public void liveOutside() {
        System.out.println("I live in the forest");
    }

    @Override
    public void loveGreens() {
        System.out.println("I eat grass");
    }
}

public class Lion extends Animal implements Carnivore, Wild {

    @Override
    public void liveOutside() {
        System.out.println("I live in the forest");
    }

    @Override
    public void loveMeat() {
        System.out.println("I eat Moose");
    }
}

Hamsterklasa dziedziczy konstrukcja z Animal, Herbivorei Petwykazują polimorficzny behawioryzm z domowego zwierzaka.

Catklasa dziedziczy strukturę od Animal, Carnivorea Pettakże wykazuje polimorficzny behawioryzm zwierzęcia domowego.

nabster
źródło