Polimorfizm vs przesłonięcie vs przeciążenie

347

Jeśli chodzi o Javę, gdy ktoś pyta:

co to jest polimorfizm?

Czy przeciążenie lub zastąpienie byłoby akceptowalną odpowiedzią?

Myślę, że jest w tym coś więcej.

JEŚLI masz abstrakcyjną klasę podstawową, która zdefiniowała metodę bez implementacji i zdefiniowałeś tę metodę w podklasie, czy to wciąż jest nadrzędne?

Myślę, że przeciążenie nie jest z pewnością właściwą odpowiedzią.

Brian G.
źródło
Poniższe odpowiedzi bardzo dobrze wyjaśniają polimorfizm. Ale mam silny sprzeciw, aby powiedzieć, że przeciążenie jest rodzajem polimorfizmu, co próbowałem uzasadnić w moim pytaniu, a odpowiedź, która faktycznie koncentruje się na przeciążeniu, jest polimorfizmem, czy nie. Próbowałem uzasadnić odpowiedź @Gabeg Gabeg w tym wątku. Zapoznaj się z opracowaniem: Przeciążenie metody to wiązanie statyczne / czas kompilacji, ale nie polimorfizm. Czy poprawne jest korelowanie wiązania statycznego z polimorfizmem?
PraveenKumar Lalasangi

Odpowiedzi:

894

Najwyraźniejszym sposobem wyrażenia polimorfizmu jest użycie abstrakcyjnej klasy bazowej (lub interfejsu)

public abstract class Human{
   ...
   public abstract void goPee();
}

Ta klasa jest abstrakcyjna, ponieważ goPee()metody nie można zdefiniować dla ludzi. Można go zdefiniować tylko w podklasach „Mężczyzna” i „Kobieta”. Ponadto człowiek jest pojęciem abstrakcyjnym - nie można stworzyć człowieka, który nie jest ani mężczyzną, ani kobietą. To musi być jeden lub drugi.

Dlatego odraczamy implementację za pomocą klasy abstrakcyjnej.

public class Male extends Human{
...
    @Override
    public void goPee(){
        System.out.println("Stand Up");
    }
}

i

public class Female extends Human{
...
    @Override
    public void goPee(){
        System.out.println("Sit Down");
    }
}

Teraz możemy powiedzieć całemu pokojowi wypełnionemu ludźmi, żeby się wysikał.

public static void main(String[] args){
    ArrayList<Human> group = new ArrayList<Human>();
    group.add(new Male());
    group.add(new Female());
    // ... add more...

    // tell the class to take a pee break
    for (Human person : group) person.goPee();
}

Uruchomienie tego spowoduje:

Stand Up
Sit Down
...
Chris Cudmore
źródło
37
@yuudachi. Wymyśliłem ten przykład podczas nauczania klasy. Kanoniczna klasa „Konto bankowe” tak naprawdę nie wyrażała „abstrakcyjności” klasy podstawowej. Drugi przykład kanoniczny (Zwierzę, hałasuj) był zbyt abstrakcyjny, by można go było zrozumieć. Szukałem jednej bazy ze zbyt oczywistymi podklasami. W rzeczywistości goPee () był jedynym przykładem, który wymyśliłem, który nie był seksistowski ani stereotypowy. (chociaż w klasie wydrukowałem „korytarzem po lewej stronie” zamiast wstać lub usiąść.)
Chris Cudmore,
100
Ten przykład również ładnie podkreśla trudność korzystania z systemu hierarchicznego do opisywania systemów biologicznych. Niektórzy ludzie, na przykład bardzo młodzi, sikają w prawie każdej pozycji - a dzieciom nie można łatwo powiedzieć, aby korzystało z goPee (). Niektórzy ludzie są interseksualni, a biologiczne znaczniki „męskiego” lub „żeńskiego” stają się raczej źle zdefiniowane; znaczenia społeczne są jeszcze bardziej złożone. Jako przykład dydaktyczny pokazuje, w jaki sposób założenia modelowania mogą mieć negatywne wyniki, takie jak implikacja, że ​​ktoś (np. Student programowania OO), który jest nietrzymający moczu lub interseksualny, w rzeczywistości nie jest człowiekiem.
Andrew Dalke
7
Mogę wymyślić przynajmniej garstkę ludzi, którzy obaliliby twoją tezę: „nie możesz stworzyć człowieka, który nie jest ani męski, ani żeński”, chociaż nadal byłoby to prawdą w twoim kodzie ... zła abstrakcja, jak sądzę, mówię ? ;)
Frank W. Zammetti
2
Myślę, że ważne jest, aby zaznaczyć, że jest to tylko polimorfizm, ponieważ którą wersję goPee () wywołać można określić tylko w czasie wykonywania. Chociaż z tego przykładu wynika, miło jest wskazać, dlaczego właśnie taki jest polimorfizm. Nie wymaga też zajęć z rodzeństwem. Może to być także relacja rodzic-dziecko. Lub nawet całkowicie niezwiązane klasy, które przypadkowo pełnią tę samą funkcję. Przykładem może być funkcja .toString (). Które można nazwać losowo na dowolnym obiekcie, ale kompilator nigdy nie może dokładnie wiedzieć, jaki typ obiektu.
Tor Valamo
20
@AndrewDalke, +1 za uwagi na temat złożoności biologicznej. Ponadto goPeenie przyjmuje pola grawitacyjnego jako danych wejściowych. Ta zależność od stanu globalnego utrudnia testowanie jednostkowe CatheterizedIntersexAstronauti pokazuje, że podklasowanie nie zawsze może być najlepszą metodą komponowania cech.
Mike Samuel
99

Polimorfizm to zdolność instancji klasy do zachowania się tak, jakby była instancją innej klasy w drzewie dziedziczenia, najczęściej jednej z klas przodków. Na przykład w Javie wszystkie klasy dziedziczą po Object. Dlatego możesz utworzyć zmienną typu Object i przypisać do niej instancję dowolnej klasy.

przesłanianiejest rodzajem funkcji występującej w klasie, która dziedziczy po innej klasie. Funkcja przesłonięcia „zastępuje” funkcję odziedziczoną z klasy podstawowej, ale robi to w taki sposób, że jest wywoływana nawet wtedy, gdy wystąpienie jej klasy udaje inny typ poprzez polimorfizm. Nawiązując do poprzedniego przykładu, możesz zdefiniować własną klasę i zastąpić funkcję toString (). Ponieważ ta funkcja jest dziedziczona z Object, będzie nadal dostępna, jeśli skopiujesz instancję tej klasy do zmiennej typu Object. Zwykle, jeśli wywołasz metodę toString () w swojej klasie, gdy udaje ona obiekt, to wersja toString, która faktycznie będzie odpalać, jest zdefiniowana w samym obiekcie. Ponieważ jednak funkcja jest przesłonięta, definicja metody toString () z Twojej klasy jest używana nawet wtedy, gdy instancja klasy „

Przeciążenie polega na zdefiniowaniu wielu metod o tej samej nazwie, ale o różnych parametrach. Nie ma to związku z nadpisywaniem ani polimorfizmem.

The Digital Gabeg
źródło
8
Jest to stare, ale polimorfizm nie oznacza, że ​​druga klasa musi znajdować się w drzewie dziedziczenia. Robi to w Javie, jeśli uważasz interfejsy za część drzewa dziedziczenia, ale nie w Go, gdzie interfejsy są implementowane niejawnie.
JN
5
W rzeczywistości nie potrzebujesz klas na polimorfizm.
StCredZero,
3
Jestem nowicjuszem i popraw mnie, jeśli się mylę, ale nie powiedziałbym, że przeciążenie nie ma związku z polimorfizmem. Przynajmniej w Javie polimorfizm występuje wtedy, gdy implementacja jest wybierana na podstawie typu obiektu wywołującego, a przeciążenie ma miejsce, gdy implementacja jest wybierana na podstawie typu parametrów, prawda? Widząc podobieństwo między nimi, pomaga mi to zrozumieć.
csjacobs24
9
Błędny. Ad hoc polymorphismjest tym, co opisałeś w sekcji Przeładowanie i jest przypadkiem polimorfizmu.
Jossie Calderon
1
„Nie ma to związku z nadpisywaniem ani polimorfizmem”. To stwierdzenie jest błędne.
Shailesh Pratapwar
45

Polimorfizm oznacza więcej niż jedną formę, ten sam obiekt wykonujący różne operacje zgodnie z wymaganiami.

Polimorfizm można osiągnąć za pomocą dwóch sposobów

  1. Przesłanianie metody
  2. Przeciążenie metody

Przeciążenie metody oznacza napisanie dwóch lub więcej metod w tej samej klasie przy użyciu tej samej nazwy metody, ale parametry przekazywania są różne.

Przesłonięcie metody oznacza, że ​​używamy nazw metod w różnych klasach, co oznacza, że ​​metoda klasy nadrzędnej jest używana w klasie potomnej.

W Javie w celu osiągnięcia polimorfizmu zmienna referencyjna superklasy może przechowywać obiekt podklasy.

Aby osiągnąć polimorfizm, każdy programista musi używać tych samych nazw metod w projekcie.

manoj
źródło
4
+1 za miłą odpowiedź. Przyjęta odpowiedź wyjaśnia tylko jeden rodzaj polimorfizmu. Ta odpowiedź jest kompletna.
apadana
1
polimorfizm jest paradygmatem (OOP), ale zastępowanie i przeciążanie są narzędziami językowymi.
曾 其 威
Polimorfizm można również osiągnąć przez rodzaj ogólny.
Minh Nghĩa
43

Oto przykład polimorfizmu w pseudo-C # / Java:

class Animal
{
    abstract string MakeNoise ();
}

class Cat : Animal {
    string MakeNoise () {
        return "Meow";
    }
}

class Dog : Animal {
    string MakeNoise () {
        return "Bark";
    }
}

Main () {
   Animal animal = Zoo.GetAnimal ();
   Console.WriteLine (animal.MakeNoise ());
}

Funkcja Main nie zna typu zwierzęcia i zależy od zachowania konkretnej implementacji metody MakeNoise ().

Edycja: Wygląda na to, że Brian pobił mnie na pięcie. Zabawne, że użyliśmy tego samego przykładu. Ale powyższy kod powinien pomóc wyjaśnić pojęcia.

Mark A. Nicolosi
źródło
To przykład polimorfizmu środowiska uruchomieniowego. Polimorfizm czasu kompilacji jest również możliwy poprzez przeciążenie metod i typy ogólne.
Pete Kirkham
Shape -> Parallelogram -> Rectangle -> Square
mpen
@ yankee2905 w tym przypadku myślę, że można użyć interfejsów, ponieważ klasa może implementować wiele interfejsów.
Sam003,
1
@Zhisheng Lub dodanie metody siusiu w abstrakcyjnej klasie nadrzędnej? Chciałbym użyć interfejsu do zaimplementowania czegoś innego.
joey rohan
43

Zarówno zastępowanie, jak i przeciążanie są wykorzystywane do osiągnięcia polimorfizmu.

Możesz mieć metodę w klasie, która jest nadpisana w jednej lub więcej podklas. Metoda robi różne rzeczy w zależności od tego, która klasa została użyta do utworzenia obiektu.

    abstract class Beverage {
       boolean isAcceptableTemperature();
    }

    class Coffee extends Beverage {
       boolean isAcceptableTemperature() { 
           return temperature > 70;
       }
    }

    class Wine extends Beverage {
       boolean isAcceptableTemperature() { 
           return temperature < 10;
       }
    }

Możesz także mieć metodę, która jest przeciążona dwoma lub więcej zestawami argumentów. Metoda robi różne rzeczy w zależności od typu przekazanych argumentów.

    class Server {
        public void pour (Coffee liquid) {
            new Cup().fillToTopWith(liquid);
        }

        public void pour (Wine liquid) {
            new WineGlass().fillHalfwayWith(liquid);
        }

        public void pour (Lemonade liquid, boolean ice) {
            Glass glass = new Glass();
            if (ice) {
                glass.fillToTopWith(new Ice());
            }
            glass.fillToTopWith(liquid);
        }
    }
Patrick McElhaney
źródło
Przypuszczam, że został odrzucony, ponieważ historycznie przeciążanie metod nie jest uważane za część polimorfizmu w paradygmacie zorientowanym obiektowo. Przeciążenie metody i polimorfizm to dwie ortogonalne, niezależne cechy języka programowania.
Sergio Acosta
7
Jak stwierdziłem w mojej odpowiedzi tutaj, nie zgadzam się - te dwie cechy nie są ortogonalne, ale są ściśle powiązane. Polimorfizm! = Dziedziczenie. Masz mój głos w górę.
Peter Meyer
2
Innymi słowy, wpisz polimorfizm vs. polimorfizm ad-hoc. Popieram tę odpowiedź, nawet jeśli nie jest tak kompletna, jak powinna, ponieważ poprawnie stwierdza, że ​​zarówno przeciążanie, jak i zastępowanie są związane z polimorfizmem. Mówienie, że polimorfizm w językach OOP może być osiągnięty tylko przez dziedziczenie klas, jest po prostu błędne - powinniśmy pamiętać, że istnieją inne języki OOP oprócz Java i C ++, w których można stosować pojęcia takie jak wielokrotne wysyłanie, polimorfizm ad hoc, polimorfizm parametryczny i tak dalej .
rsenna
2
@rsenna To może być niekompletne, ale odpowiada na pytanie znacznie lepiej niż reszta IMHO. Bardzo miło, że wspomniałeś o polimorfizmie ad-hoc i parametrycznym.
Valentin Radu,
15

Masz rację, że przeciążenie nie jest odpowiedzią.

Żadne nie jest nadrzędne. Przesłanianie to sposób, w jaki uzyskujesz polimorfizm. Polimorfizm to zdolność obiektu do zmiany zachowania w zależności od jego typu. Najlepiej jest to wykazane, gdy obiekt wywołujący polimorfizm nie jest świadomy tego, jaki jest konkretny typ obiektu.

Alex B.
źródło
3
Zmienia się nie zachowanie obiektu, ale jego implementacja. To samo zachowanie, inna implementacja, to polimorfizm.
QBziZ
@QBziZ Musisz określić zachowanie , zwłaszcza przymiotnik sam . Jeśli zachowanie jest takie samo, dlaczego ich implementacja powinna być inna? Nie jest tak, że ktoś jest niezadowolony z określonej implementacji, dlatego wymaga innej.
Sнаđошƒаӽ
11

Mówiąc konkretnie, przeciążenie lub zastąpienie nie daje pełnego obrazu. Polimorfizm to po prostu zdolność obiektu do specjalizacji swojego zachowania w zależności od jego typu.

Nie zgadzam się z niektórymi odpowiedziami tutaj, ponieważ przeciążenie jest formą polimorfizmu (polimorfizm parametryczny) w przypadku, gdy metoda o tej samej nazwie może zachowywać się inaczej, dając różne typy parametrów. Dobrym przykładem jest przeciążenie operatora. Możesz zdefiniować „+”, aby akceptować różne typy parametrów - powiedzmy łańcuchy lub int - i na podstawie tych typów „+” będzie się zachowywać inaczej.

Polimorfizm obejmuje także metody dziedziczenia i przesłonięcia, chociaż mogą być abstrakcyjne lub wirtualne w typie podstawowym. Jeśli chodzi o polimorfizm oparty na dziedziczeniu, Java obsługuje tylko dziedziczenie pojedynczej klasy, co ogranicza zachowanie polimorficzne do pojedynczego łańcucha typów podstawowych. Java obsługuje implementację wielu interfejsów, co jest kolejną formą zachowania polimorficznego.

Peter Meyer
źródło
Masz rację, jeśli chodzi o znaczenie słów, ale w kontekście programowania, kiedy ludzie mówią „polimorfizm”, zawsze oznaczają „polimorfizm oparty na dziedziczeniu”. Interesujący punkt, ale myślę, że opisanie polimorfizmu w ten sposób wprowadzi ludzi w błąd.
The Digital Gabeg,
Polimorfizm może być łatwiejszy do wyjaśnienia w kategoriach samego dziedziczenia, ale sposób, w jaki zadano to konkretne pytanie, uważam, że rozsądne jest również opisanie polimorfizmu parametrycznego.
Patrick McElhaney
4
Dla jasności uważam, że należy podać różne formularze - których nawet nie zrobiłem odpowiednio - ponieważ jest tutaj kilka odpowiedzi, które są przedstawione jako bezwzględne. Z szacunkiem nie zgadzam się z tym, że w „kontekście programisty ...” polimorfizm ”zawsze oznacza„ polimorfizm oparty na dziedziczeniu ””
Peter Meyer
2
myślę, że przeciążenie jest lepiej sklasyfikowane jako Ad-hoc_polymorphism en.wikipedia.org/wiki/…
Manu
Zgadzam się z „The Digital Gabeg” co do następujących. Jeśli dyskutujesz na temat OOP, polimorfizm zwykle oznacza polimorfizm podtypu, a jeśli dyskutujesz na temat teorii typów, oznacza to dowolny rodzaj polimorfizmu. Ale, jak mówisz, w „kontekście programisty” zbyt dwuznaczne jest wyśmiewanie.
Manu,
7

Polimorfizm oznacza po prostu „Wiele form”.

Nie jest wymagane dziedziczenie w celu osiągnięcia ... ponieważ implementacja interfejsu, która wcale nie jest dziedziczeniem, spełnia potrzeby polimorficzne. Prawdopodobnie implementacja interfejsu spełnia potrzeby polimorficzne „Lepsze” niż dziedziczenie.

Na przykład, czy stworzyłbyś superklasę do opisywania wszystkich rzeczy, które potrafią latać? Nie powinienem myśleć. Najlepiej byłoby, gdybyś stworzył interfejs opisujący lot i zostaw to.

Ponieważ interfejsy opisują zachowanie, a nazwy metod opisują zachowanie (dla programisty), rozważenie przeciążenia metody jako mniejszej formy polimorfizmu nie jest zbyt daleko idące.

BillC
źródło
2
Zdecydowanie najlepsza jak dotąd odpowiedź. Polimorfizm można zastosować do wszystkich konstrukcji językowych, czy to rzeczowników (klas), czy czasowników (metod).
Radu Gasler
6

Klasyczny przykład: Psy i koty to zwierzęta, zwierzęta mają metodę makeNoise. Mogę iterować przez szereg zwierząt wywołujących na nich makeNoise i oczekuję, że zrobią tam odpowiednią implementację.

Kod wywoławczy nie musi wiedzieć, jakie to konkretne zwierzę.

To, co uważam za polimorfizm.

Brian G.
źródło
4

Polimorfizm to zdolność obiektu do pojawiania się w wielu formach. Wiąże się to z wykorzystaniem funkcji dziedziczenia i funkcji wirtualnych do zbudowania rodziny obiektów, które można zamieniać. Klasa podstawowa zawiera prototypy funkcji wirtualnych, być może niezaimplementowanych lub z domyślnymi implementacjami, jak nakazuje aplikacja, a każda z różnych klas pochodnych implementuje je inaczej, aby wpływać na różne zachowania.

Mxg
źródło
4

Ani:

Przeciążenie występuje wtedy, gdy masz tę samą nazwę funkcji, która przyjmuje różne parametry.

Przesłanianie ma miejsce wtedy, gdy klasa potomna zastępuje metodę rodzica jedną z jej własnych (to samo w sobie nie stanowi polimorfizmu).

Polimorfizm wiąże się późno, np. Wywoływane są metody klasy podstawowej (rodzicielskiej), ale dopiero wtedy, gdy środowisko wykonawcze dowie się, jaki jest rzeczywisty obiekt - może to być klasa potomna, której metody są różne. Wynika to z faktu, że można użyć dowolnej klasy potomnej, w której zdefiniowano klasę podstawową.

W Javie często spotyka się polimorfizm w bibliotece kolekcji:

int countStuff(List stuff) {
  return stuff.size();
}

Lista jest klasą podstawową, kompilator nie ma pojęcia, czy liczy się lista połączona, wektor, tablica lub niestandardowa implementacja listy, o ile działa ona jak Lista:

List myStuff = new MyTotallyAwesomeList();
int result = countStuff(myStuff);

Gdybyś był przeciążony, miałbyś:

int countStuff(LinkedList stuff) {...}
int countStuff(ArrayList stuff) {...}
int countStuff(MyTotallyAwesomeList stuff) {...}
etc...

a kompilator wybierze poprawną wersję countStuff (), aby dopasować parametry.

jpeacock
źródło
4

Chociaż polimorfizm jest już szczegółowo wyjaśniony w tym poście, ale chciałbym położyć większy nacisk na jego część.

Dlaczego polimorfizm jest tak ważny w każdym języku OOP.

Spróbujmy zbudować prostą aplikację do telewizora z dziedziczeniem / polimorfizmem i bez niego. Po każdej wersji aplikacji wykonujemy małą retrospektywę.

Załóżmy, że jesteś inżynierem oprogramowania w firmie telewizyjnej i jesteś proszony o napisanie oprogramowania dla kontrolerów głośności, jasności i koloru, aby zwiększyć lub zmniejszyć ich wartości na polecenie użytkownika.

Zaczynasz od pisania zajęć dla każdej z tych funkcji, dodając

  1. set: - Aby ustawić wartość kontrolera. (Załóżmy, że ma kod specyficzny dla kontrolera)
  2. get: - Aby uzyskać wartość kontrolera. (Załóżmy, że ma kod specyficzny dla kontrolera)
  3. dostosuj: - Aby sprawdzić poprawność wejścia i ustawienie kontrolera. (Ogólne sprawdzanie poprawności .. niezależne od kontrolerów)
  4. mapowanie danych wejściowych użytkownika za pomocą kontrolerów: - Aby odpowiednio wprowadzić dane użytkownika i wywołać kontrolery.

Wersja aplikacji 1

import java.util.Scanner;    
class VolumeControllerV1 {
    private int value;
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of VolumeController \t"+this.value);
        this.value = value;
        System.out.println("New value of VolumeController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}
class  BrightnessControllerV1 {
    private int value;
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of BrightnessController \t"+this.value);
        this.value = value;
        System.out.println("New value of BrightnessController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}
class ColourControllerV1    {
    private int value;
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of ColourController \t"+this.value);
        this.value = value;
        System.out.println("New value of ColourController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}

/*
 *       There can be n number of controllers
 * */
public class TvApplicationV1 {
    public static void main(String[] args)  {
        VolumeControllerV1 volumeControllerV1 = new VolumeControllerV1();
        BrightnessControllerV1 brightnessControllerV1 = new BrightnessControllerV1();
        ColourControllerV1 colourControllerV1 = new ColourControllerV1();


        OUTER: while(true) {
            Scanner sc=new Scanner(System.in);
            System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume");
            System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness");
            System.out.println(" Press 5 to increase color \n Press 6 to decrease color");
            System.out.println("Press any other Button to shutdown");
            int button = sc.nextInt();
            switch (button) {
                case  1:    {
                    volumeControllerV1.adjust(5);
                    break;
                }
                case 2: {
                    volumeControllerV1.adjust(-5);
                    break;
                }
                case  3:    {
                    brightnessControllerV1.adjust(5);
                    break;
                }
                case 4: {
                    brightnessControllerV1.adjust(-5);
                    break;
                }
                case  5:    {
                    colourControllerV1.adjust(5);
                    break;
                }
                case 6: {
                colourControllerV1.adjust(-5);
                break;
            }
            default:
                System.out.println("Shutting down...........");
                break OUTER;
        }

    }
    }
}

Teraz masz naszą pierwszą wersję działającej aplikacji gotową do wdrożenia. Czas przeanalizować dotychczasowe prace.

Problemy w aplikacji telewizyjnej w wersji 1

  1. Kod dostosowania (wartość całkowita) jest duplikowany we wszystkich trzech klasach. Chcesz zminimalizować podwójność kodu. (Ale nie pomyślałeś o wspólnym kodzie i przeniesieniu go do jakiejś superklasy, aby uniknąć powielania kodu)

Postanawiasz żyć z tym tak długo, jak długo aplikacja będzie działać zgodnie z oczekiwaniami.

Po pewnym czasie szef wraca do Ciebie i prosi o dodanie funkcji resetowania do istniejącej aplikacji. Reset zresetuje wszystkie 3 trzy kontrolery do ich odpowiednich wartości domyślnych.

Zaczynasz pisać nową klasę (ResetFunctionV2) dla nowej funkcjonalności i mapujesz wejściowy kod mapowania dla tej nowej funkcji.

Wersja aplikacji 2

import java.util.Scanner;
class VolumeControllerV2    {

    private int defaultValue = 25;
    private int value;

    int getDefaultValue() {
        return defaultValue;
    }
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of VolumeController \t"+this.value);
        this.value = value;
        System.out.println("New value of VolumeController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}
class  BrightnessControllerV2   {

    private int defaultValue = 50;
    private int value;
    int get()    {
        return value;
    }
    int getDefaultValue() {
        return defaultValue;
    }
    void set(int value) {
        System.out.println("Old value of BrightnessController \t"+this.value);
        this.value = value;
        System.out.println("New value of BrightnessController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}
class ColourControllerV2    {

    private int defaultValue = 40;
    private int value;
    int get()    {
        return value;
    }
    int getDefaultValue() {
        return defaultValue;
    }
    void set(int value) {
        System.out.println("Old value of ColourController \t"+this.value);
        this.value = value;
        System.out.println("New value of ColourController \t"+this.value);
    }
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}

class ResetFunctionV2 {

    private VolumeControllerV2 volumeControllerV2 ;
    private BrightnessControllerV2 brightnessControllerV2;
    private ColourControllerV2 colourControllerV2;

    ResetFunctionV2(VolumeControllerV2 volumeControllerV2, BrightnessControllerV2 brightnessControllerV2, ColourControllerV2 colourControllerV2)  {
        this.volumeControllerV2 = volumeControllerV2;
        this.brightnessControllerV2 = brightnessControllerV2;
        this.colourControllerV2 = colourControllerV2;
    }
    void onReset()    {
        volumeControllerV2.set(volumeControllerV2.getDefaultValue());
        brightnessControllerV2.set(brightnessControllerV2.getDefaultValue());
        colourControllerV2.set(colourControllerV2.getDefaultValue());
    }
}
/*
 *       so on
 *       There can be n number of controllers
 *
 * */
public class TvApplicationV2 {
    public static void main(String[] args)  {
        VolumeControllerV2 volumeControllerV2 = new VolumeControllerV2();
        BrightnessControllerV2 brightnessControllerV2 = new BrightnessControllerV2();
        ColourControllerV2 colourControllerV2 = new ColourControllerV2();

        ResetFunctionV2 resetFunctionV2 = new ResetFunctionV2(volumeControllerV2, brightnessControllerV2, colourControllerV2);

        OUTER: while(true) {
            Scanner sc=new Scanner(System.in);
            System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume");
            System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness");
            System.out.println(" Press 5 to increase color \n Press 6 to decrease color");
            System.out.println(" Press 7 to reset TV \n Press any other Button to shutdown");
            int button = sc.nextInt();
            switch (button) {
                case  1:    {
                    volumeControllerV2.adjust(5);
                    break;
                }
                case 2: {
                    volumeControllerV2.adjust(-5);
                    break;
                }
                case  3:    {
                    brightnessControllerV2.adjust(5);
                    break;
                }
                case 4: {
                    brightnessControllerV2.adjust(-5);
                    break;
                }
                case  5:    {
                    colourControllerV2.adjust(5);
                    break;
                }
                case 6: {
                    colourControllerV2.adjust(-5);
                    break;
                }
                case 7: {
                    resetFunctionV2.onReset();
                    break;
                }
                default:
                    System.out.println("Shutting down...........");
                    break OUTER;
            }

        }
    }
}

Przygotuj aplikację dzięki funkcji Reset. Ale teraz zaczynasz zdawać sobie z tego sprawę

Problemy w aplikacji telewizyjnej w wersji 2

  1. Jeśli do produktu zostanie wprowadzony nowy kontroler, musisz zmienić kod opcji Resetuj.
  2. Jeśli liczba kontrolerów rośnie bardzo wysoko, możesz mieć problem z przechowywaniem referencji kontrolerów.
  3. Resetuj kod opcji jest ściśle powiązany ze wszystkimi kodami klasy kontrolerów (aby uzyskać i ustawić wartości domyślne).
  4. Resetuj klasę funkcji (ResetFunctionV2) może uzyskać dostęp do innej metody klasy Controller (dostosuj), co jest niepożądane.

Jednocześnie słyszysz od szefa, że ​​może być konieczne dodanie funkcji, w której każdy kontroler podczas uruchamiania musi sprawdzić najnowszą wersję sterownika z firmowego repozytorium sterowników przez Internet.

Teraz zaczynasz myśleć, że ta nowa funkcja, która ma zostać dodana, przypomina funkcję Resetuj, a problemy z aplikacją (V2) zostaną pomnożone, jeśli nie zmienisz współczynnika swojej aplikacji.

Zaczynasz myśleć o używaniu dziedziczenia, aby móc skorzystać z polimorficznej zdolności JAVA i dodajesz nową klasę abstrakcyjną (ControllerV3) do

  1. Zadeklaruj podpis metody get i set.
  2. Zawierają implementację metody dostosowania, która została wcześniej zreplikowana wśród wszystkich kontrolerów.
  3. Zadeklaruj metodę setDefault, aby funkcja resetowania mogła być łatwo zaimplementowana z wykorzystaniem polimorfizmu.

Dzięki tym ulepszeniom masz gotową wersję 3 aplikacji telewizyjnej.

Wersja aplikacji 3

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

abstract class ControllerV3 {
    abstract void set(int value);
    abstract int get();
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
    abstract void setDefault();
}
class VolumeControllerV3 extends ControllerV3   {

    private int defaultValue = 25;
    private int value;

    public void setDefault() {
        set(defaultValue);
    }
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of VolumeController \t"+this.value);
        this.value = value;
        System.out.println("New value of VolumeController \t"+this.value);
    }
}
class  BrightnessControllerV3  extends ControllerV3   {

    private int defaultValue = 50;
    private int value;

    public void setDefault() {
        set(defaultValue);
    }
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of BrightnessController \t"+this.value);
        this.value = value;
        System.out.println("New value of BrightnessController \t"+this.value);
    }
}
class ColourControllerV3 extends ControllerV3   {

    private int defaultValue = 40;
    private int value;

    public void setDefault() {
        set(defaultValue);
    }
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of ColourController \t"+this.value);
        this.value = value;
        System.out.println("New value of ColourController \t"+this.value);
    }
}

class ResetFunctionV3 {

    private List<ControllerV3> controllers = null;

    ResetFunctionV3(List<ControllerV3> controllers)  {
        this.controllers = controllers;
    }
    void onReset()    {
        for (ControllerV3 controllerV3 :this.controllers)  {
            controllerV3.setDefault();
        }
    }
}
/*
 *       so on
 *       There can be n number of controllers
 *
 * */
public class TvApplicationV3 {
    public static void main(String[] args)  {
        VolumeControllerV3 volumeControllerV3 = new VolumeControllerV3();
        BrightnessControllerV3 brightnessControllerV3 = new BrightnessControllerV3();
        ColourControllerV3 colourControllerV3 = new ColourControllerV3();

        List<ControllerV3> controllerV3s = new ArrayList<>();
        controllerV3s.add(volumeControllerV3);
        controllerV3s.add(brightnessControllerV3);
        controllerV3s.add(colourControllerV3);

        ResetFunctionV3 resetFunctionV3 = new ResetFunctionV3(controllerV3s);

        OUTER: while(true) {
            Scanner sc=new Scanner(System.in);
            System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume");
            System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness");
            System.out.println(" Press 5 to increase color \n Press 6 to decrease color");
            System.out.println(" Press 7 to reset TV \n Press any other Button to shutdown");
            int button = sc.nextInt();
            switch (button) {
                case  1:    {
                    volumeControllerV3.adjust(5);
                    break;
                }
                case 2: {
                    volumeControllerV3.adjust(-5);
                    break;
                }
                case  3:    {
                    brightnessControllerV3.adjust(5);
                    break;
                }
                case 4: {
                    brightnessControllerV3.adjust(-5);
                    break;
                }
                case  5:    {
                    colourControllerV3.adjust(5);
                    break;
                }
                case 6: {
                    colourControllerV3.adjust(-5);
                    break;
                }
                case 7: {
                    resetFunctionV3.onReset();
                    break;
                }
                default:
                    System.out.println("Shutting down...........");
                    break OUTER;
            }

        }
    }
}

Chociaż większość problemów wymienionych na liście problemów w wersji V2 została rozwiązana z wyjątkiem

Problemy w aplikacji telewizyjnej w wersji 3

  1. Resetuj klasę funkcji (ResetFunctionV3) może uzyskać dostęp do innej metody klasy Controller (dostosuj), co jest niepożądane.

Znowu myślisz o rozwiązaniu tego problemu, ponieważ teraz masz także inną funkcję (aktualizacja sterownika przy uruchomieniu). Jeśli go nie naprawisz, zostanie również zreplikowane do nowych funkcji.

Dzielisz więc kontrakt zdefiniowany w klasie abstrakcyjnej i piszesz 2 interfejsy

  1. Zresetuj funkcję.
  2. Aktualizacja sterownika.

I niech twoja pierwsza konkretna klasa zastosuje je jak poniżej

Wersja aplikacji 4

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

interface OnReset {
    void setDefault();
}
interface OnStart {
    void checkForDriverUpdate();
}
abstract class ControllerV4 implements OnReset,OnStart {
    abstract void set(int value);
    abstract int get();
    void adjust(int value)  {
        int temp = this.get();
        if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0)))    {
            System.out.println("Can not adjust any further");
            return;
        }
        this.set(temp + value);
    }
}

class VolumeControllerV4 extends ControllerV4 {

    private int defaultValue = 25;
    private int value;
    @Override
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of VolumeController \t"+this.value);
        this.value = value;
        System.out.println("New value of VolumeController \t"+this.value);
    }
    @Override
    public void setDefault() {
        set(defaultValue);
    }

    @Override
    public void checkForDriverUpdate()    {
        System.out.println("Checking driver update for VolumeController .... Done");
    }
}
class  BrightnessControllerV4 extends ControllerV4 {

    private int defaultValue = 50;
    private int value;
    @Override
    int get()    {
        return value;
    }
    @Override
    void set(int value) {
        System.out.println("Old value of BrightnessController \t"+this.value);
        this.value = value;
        System.out.println("New value of BrightnessController \t"+this.value);
    }

    @Override
    public void setDefault() {
        set(defaultValue);
    }

    @Override
    public void checkForDriverUpdate()    {
        System.out.println("Checking driver update for BrightnessController .... Done");
    }
}
class ColourControllerV4 extends ControllerV4 {

    private int defaultValue = 40;
    private int value;
    @Override
    int get()    {
        return value;
    }
    void set(int value) {
        System.out.println("Old value of ColourController \t"+this.value);
        this.value = value;
        System.out.println("New value of ColourController \t"+this.value);
    }
    @Override
    public void setDefault() {
        set(defaultValue);
    }

    @Override
    public void checkForDriverUpdate()    {
        System.out.println("Checking driver update for ColourController .... Done");
    }
}
class ResetFunctionV4 {

    private List<OnReset> controllers = null;

    ResetFunctionV4(List<OnReset> controllers)  {
        this.controllers = controllers;
    }
    void onReset()    {
        for (OnReset onreset :this.controllers)  {
            onreset.setDefault();
        }
    }
}
class InitializeDeviceV4 {

    private List<OnStart> controllers = null;

    InitializeDeviceV4(List<OnStart> controllers)  {
        this.controllers = controllers;
    }
    void initialize()    {
        for (OnStart onStart :this.controllers)  {
            onStart.checkForDriverUpdate();
        }
    }
}
/*
*       so on
*       There can be n number of controllers
*
* */
public class TvApplicationV4 {
    public static void main(String[] args)  {
        VolumeControllerV4 volumeControllerV4 = new VolumeControllerV4();
        BrightnessControllerV4 brightnessControllerV4 = new BrightnessControllerV4();
        ColourControllerV4 colourControllerV4 = new ColourControllerV4();
        List<ControllerV4> controllerV4s = new ArrayList<>();
        controllerV4s.add(brightnessControllerV4);
        controllerV4s.add(volumeControllerV4);
        controllerV4s.add(colourControllerV4);

        List<OnStart> controllersToInitialize = new ArrayList<>();
        controllersToInitialize.addAll(controllerV4s);
        InitializeDeviceV4 initializeDeviceV4 = new InitializeDeviceV4(controllersToInitialize);
        initializeDeviceV4.initialize();

        List<OnReset> controllersToReset = new ArrayList<>();
        controllersToReset.addAll(controllerV4s);
        ResetFunctionV4 resetFunctionV4 = new ResetFunctionV4(controllersToReset);

        OUTER: while(true) {
            Scanner sc=new Scanner(System.in);
            System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume");
            System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness");
            System.out.println(" Press 5 to increase color \n Press 6 to decrease color");
            System.out.println(" Press 7 to reset TV \n Press any other Button to shutdown");
            int button = sc.nextInt();
            switch (button) {
                case  1:    {
                    volumeControllerV4.adjust(5);
                    break;
                }
                case 2: {
                    volumeControllerV4.adjust(-5);
                    break;
                }
                case  3:    {
                    brightnessControllerV4.adjust(5);
                    break;
                }
                case 4: {
                    brightnessControllerV4.adjust(-5);
                    break;
                }
                case  5:    {
                    colourControllerV4.adjust(5);
                    break;
                }
                case 6: {
                    colourControllerV4.adjust(-5);
                    break;
                }
                case 7: {
                    resetFunctionV4.onReset();
                    break;
                }
                default:
                    System.out.println("Shutting down...........");
                    break OUTER;
            }

        }
    }
}

Teraz wszystkie problemy, z którymi się spotkałeś, zostały rozwiązane i zdałeś sobie sprawę, że dzięki Dziedziczeniu i Polimorfizmowi możesz

  1. Zachowaj luźne powiązanie różnych części aplikacji (składniki funkcji resetowania lub aktualizacji sterownika nie muszą być informowane o rzeczywistych klasach kontrolerów (objętość, jasność i kolor), każda klasa implementująca OnReset lub OnStart będzie akceptowalna do resetowania lub aktualizacji sterownika odpowiednio składniki).
  2. Ulepszanie aplikacji staje się łatwiejsze (nowy dodatek kontrolera nie wpłynie na reset lub składnik funkcji aktualizacji sterownika, a teraz możesz naprawdę łatwo dodawać nowe)
  3. Zachowaj warstwę abstrakcji. (Teraz funkcja Resetuj widzi tylko metodę kontrolerów setDefault, a funkcja Resetu widzi tylko metodę kontrolerów checkForDriverUpdate)

Mam nadzieję że to pomoże :-)

Deweloper
źródło
3

Termin przeciążenie odnosi się do posiadania wielu wersji czegoś o tej samej nazwie, zwykle metod o różnych listach parametrów

public int DoSomething(int objectId) { ... }
public int DoSomething(string objectName) { ... }

Więc te funkcje mogą zrobić to samo, ale masz możliwość wywołania go z identyfikatorem lub nazwą. Nie ma nic wspólnego z dziedziczeniem, klasami abstrakcyjnymi itp.

Przesłanianie zwykle odnosi się do polimorfizmu, jak opisano w pytaniu

Clyde
źródło
2

przeciążenie ma miejsce, gdy zdefiniujesz 2 metody o tej samej nazwie, ale o różnych parametrach

przesłonięcie polega na zmianie zachowania klasy podstawowej za pomocą funkcji o tej samej nazwie w podklasie.

Polimorfizm jest więc związany z nadpisywaniem, ale nie przeciążaniem.

Jeśli jednak ktoś dał mi prostą odpowiedź „nadpisanie” na pytanie „Co to jest polimorfizm?” Poprosiłbym o dalsze wyjaśnienia.

Matt
źródło
2

przesłonięcie jest bardziej jak ukrywanie odziedziczonej metody poprzez zadeklarowanie metody o takiej samej nazwie i sygnaturze jak metoda wyższego poziomu (super metoda), to dodaje zachowanie polimorficzne do klasy. innymi słowy, decyzja o wyborze metody poziomu, która ma zostać wywołana, zostanie podjęta w czasie wykonywania, a nie w czasie kompilacji. prowadzi to do koncepcji interfejsu i implementacji.

Genjuro
źródło
2

co to jest polimorfizm?

Z java samouczka

Słownikowa definicja polimorfizmu odnosi się do zasady w biologii, w której organizm lub gatunek może mieć wiele różnych form lub stadiów. Zasadę tę można także zastosować do programowania obiektowego i języków takich jak język Java. Podklasy klasy mogą definiować własne unikalne zachowania, a jednocześnie udostępniać niektóre z tych samych funkcji klasy nadrzędnej.

Biorąc pod uwagę przykłady i definicję, zastępowanie powinny być zaakceptowane odpowiedź.

Jeśli chodzi o twoje drugie zapytanie:

JEŚLI masz abstrakcyjną klasę podstawową, która zdefiniowała metodę bez implementacji i zdefiniowałeś tę metodę w podklasie, czy to wciąż jest nadrzędne?

Należy to nazwać przesłonięciem.

Spójrz na ten przykład, aby zrozumieć różne typy zastępowania.

  1. Klasa podstawowa nie zapewnia implementacji, a podklasa musi zastąpić pełną metodę - (abstrakt)
  2. Klasa podstawowa zapewnia domyślną implementację, a podklasa może zmienić zachowanie
  3. Podklasa dodaje rozszerzenie do implementacji klasy podstawowej, wywołując super.methodName()jako pierwszą instrukcję
  4. Klasa podstawowa określa strukturę algorytmu (metoda szablonu), a podklasa zastąpi część algorytmu

fragment kodu:

import java.util.HashMap;

abstract class Game implements Runnable{

    protected boolean runGame = true;
    protected Player player1 = null;
    protected Player player2 = null;
    protected Player currentPlayer = null;

    public Game(){
        player1 = new Player("Player 1");
        player2 = new Player("Player 2");
        currentPlayer = player1;
        initializeGame();
    }

    /* Type 1: Let subclass define own implementation. Base class defines abstract method to force
        sub-classes to define implementation    
    */

    protected abstract void initializeGame();

    /* Type 2: Sub-class can change the behaviour. If not, base class behaviour is applicable */
    protected void logTimeBetweenMoves(Player player){
        System.out.println("Base class: Move Duration: player.PlayerActTime - player.MoveShownTime");
    }

    /* Type 3: Base class provides implementation. Sub-class can enhance base class implementation by calling
        super.methodName() in first line of the child class method and specific implementation later */
    protected void logGameStatistics(){
        System.out.println("Base class: logGameStatistics:");
    }
    /* Type 4: Template method: Structure of base class can't be changed but sub-class can some part of behaviour */
    protected void runGame() throws Exception{
        System.out.println("Base class: Defining the flow for Game:");  
        while ( runGame) {
            /*
            1. Set current player
            2. Get Player Move
            */
            validatePlayerMove(currentPlayer);  
            logTimeBetweenMoves(currentPlayer);
            Thread.sleep(500);
            setNextPlayer();
        }
        logGameStatistics();
    }
    /* sub-part of the template method, which define child class behaviour */
    protected abstract void validatePlayerMove(Player p);

    protected void setRunGame(boolean status){
        this.runGame = status;
    }
    public void setCurrentPlayer(Player p){
        this.currentPlayer = p;
    }
    public void setNextPlayer(){
        if ( currentPlayer == player1) {
            currentPlayer = player2;
        }else{
            currentPlayer = player1;
        }
    }
    public void run(){
        try{
            runGame();
        }catch(Exception err){
            err.printStackTrace();
        }
    }
}

class Player{
    String name;
    Player(String name){
        this.name = name;
    }
    public String getName(){
        return name;
    }
}

/* Concrete Game implementation  */
class Chess extends Game{
    public Chess(){
        super();
    }
    public void initializeGame(){
        System.out.println("Child class: Initialized Chess game");
    }
    protected void validatePlayerMove(Player p){
        System.out.println("Child class: Validate Chess move:"+p.getName());
    }
    protected void logGameStatistics(){
        super.logGameStatistics();
        System.out.println("Child class: Add Chess specific logGameStatistics:");
    }
}
class TicTacToe extends Game{
    public TicTacToe(){
        super();
    }
    public void initializeGame(){
        System.out.println("Child class: Initialized TicTacToe game");
    }
    protected void validatePlayerMove(Player p){
        System.out.println("Child class: Validate TicTacToe move:"+p.getName());
    }
}

public class Polymorphism{
    public static void main(String args[]){
        try{

            Game game = new Chess();
            Thread t1 = new Thread(game);
            t1.start();
            Thread.sleep(1000);
            game.setRunGame(false);
            Thread.sleep(1000);

            game = new TicTacToe();
            Thread t2 = new Thread(game);
            t2.start();
            Thread.sleep(1000);
            game.setRunGame(false);

        }catch(Exception err){
            err.printStackTrace();
        }       
    }
}

wynik:

Child class: Initialized Chess game
Base class: Defining the flow for Game:
Child class: Validate Chess move:Player 1
Base class: Move Duration: player.PlayerActTime - player.MoveShownTime
Child class: Validate Chess move:Player 2
Base class: Move Duration: player.PlayerActTime - player.MoveShownTime
Base class: logGameStatistics:
Child class: Add Chess specific logGameStatistics:
Child class: Initialized TicTacToe game
Base class: Defining the flow for Game:
Child class: Validate TicTacToe move:Player 1
Base class: Move Duration: player.PlayerActTime - player.MoveShownTime
Child class: Validate TicTacToe move:Player 2
Base class: Move Duration: player.PlayerActTime - player.MoveShownTime
Base class: logGameStatistics:
Ravindra babu
źródło
2

Myślę, że faceci mieszają koncepcje. Polimorfizm to zdolność obiektu do zachowania się inaczej w czasie wykonywania. Aby to osiągnąć, potrzebujesz dwóch wymagań:

  1. Późne wiązanie
  2. Dziedzictwo.

Powiedziawszy, że przeciążenie oznacza coś innego niż zastąpienie w zależności od używanego języka. Na przykład w Javie nie istnieje nadpisywanie, ale przeciążanie . Przeciążone metody z inną sygnaturą niż klasa podstawowa są dostępne w podklasie. W przeciwnym razie zostałyby zastąpione (proszę zauważyć, że mam na myśli fakt, że nie ma możliwości wywołania metody klasy bazowej spoza obiektu).

Jednak w C ++ tak nie jest. Każda przeciążona metoda, niezależnie od tego, czy podpis jest taki sam, czy nie (różna ilość, inny typ) jest również zastępowana . To znaczy, że metoda klasy bazowej nie jest już dostępna w podklasie, kiedy jest wywoływana spoza obiektu podklasy, oczywiście.

Więc odpowiedź brzmi, gdy mówimy o przeciążeniu Java . W każdym innym języku może być inny, jak to się dzieje w c ++

użytkownik1154840
źródło
1

Polimorfizm jest bardziej prawdopodobny, jeśli chodzi o jego znaczenie ... OVERRIDING w java

Chodzi o różne zachowanie obiektu SAME w różnych sytuacjach (w sposób programowania ... możesz wywoływać różne ARGUMENTY)

Myślę, że poniższy przykład pomoże ci zrozumieć ... Chociaż nie jest to czysty kod Java ...

     public void See(Friend)
     {
        System.out.println("Talk");
     }

Ale jeśli zmienimy ARGUMENT ... ZACHOWANIE zostanie zmienione ...

     public void See(Enemy)
     {
        System.out.println("Run");
     }

Osoba (tutaj „Obiekt”) jest taka sama ...

Rajan
źródło
1

Polimorfizm to wiele implementacji obiektu lub można powiedzieć wiele form obiektu. Powiedzmy, że masz klasę Animalsjako abstrakcyjną klasę podstawową i ma ona metodę o nazwie, movement()która określa sposób poruszania się zwierzęcia. Teraz w rzeczywistości mamy różne rodzaje zwierząt i poruszają się one inaczej, niektóre z nich mają 2 nogi, inne z 4 i niektóre bez nóg itp. Aby zdefiniować różne movement()dla każdego zwierzęcia na ziemi, musimy zastosować polimorfizm. Musisz jednak zdefiniować więcej klas, tj. Klas Dogs Cats Fishitp. Następnie musisz rozszerzyć te klasy z klasy podstawowej Animalsi zastąpić jej metodęmovement() nową funkcją ruchu opartą na każdym zwierzęciu, które posiadasz. Możesz także użyćInterfacesaby to osiągnąć. Słowo kluczowe tutaj jest nadrzędne, przeciążenie jest inne i nie jest uważane za polimorfizm. przy przeciążeniu możesz zdefiniować wiele metod „o tej samej nazwie”, ale o różnych parametrach w tym samym obiekcie lub klasie.

SolidSnake
źródło
0

Polimorfizm dotyczy zdolności języka do równomiernego traktowania różnych obiektów za pomocą pojedynczych interfejsów; jako taki jest związany z przesłonięciem, więc interfejs (lub klasa podstawowa) jest polimorficzny, implementator jest obiektem, który przesłania (dwie ściany tego samego medalu)

w każdym razie różnicę między tymi dwoma terminami lepiej wyjaśnić za pomocą innych języków, takich jak c ++: obiekt polimorficzny w c ++ zachowuje się jak odpowiednik java, jeśli funkcja podstawowa jest wirtualna, ale jeśli metoda nie jest wirtualna, skok kodu jest rozstrzygany statycznie , a prawdziwy typ nie jest sprawdzany w czasie wykonywania, więc polimorfizm obejmuje zdolność obiektu do zachowania się inaczej w zależności od interfejsu użytego do uzyskania do niego dostępu; dam przykład w pseudokodzie:

class animal {
    public void makeRumor(){
        print("thump");
    }
}
class dog extends animal {
    public void makeRumor(){
        print("woff");
    }
}

animal a = new dog();
dog b = new dog();

a.makeRumor() -> prints thump
b.makeRumor() -> prints woff

(zakładając, że makeRumor NIE jest wirtualny)

java tak naprawdę nie oferuje tego poziomu polimorfizmu (zwanego także krojeniem obiektów).

zwierzę a = nowy pies (); pies b = nowy pies ();

a.makeRumor() -> prints thump
b.makeRumor() -> prints woff

w obu przypadkach wypisuje tylko woff .. ponieważ aib odnosi się do psa klasy

Lorenzo Boccaccia
źródło
zwierzę a = nowy pies (); został skonstruowany jako pies i wydrukuje „woff”. Jeśli chcesz, aby wydrukował łomot, musisz go wyrzucić. ((Zwierzę) a) .makeRumor ()
Chris Cudmore
To jest upcasting referencyjny, ale obiekt wciąż jest psem. Jeśli chcesz, aby było to zwierzę, musisz jawnie wyrzucić z góry obiekt.
Chris Cudmore,
Domyśliłam się. Pytanie zostało oznaczone tagiem Java. Odpowiedziałeś na C ++. Być może masz rację w C ++. Jestem zdecydowanie poprawny w Javie.
Chris Cudmore,
powinien się zdarzyć za każdym razem, gdy zaangażowany jest tutaj konstruktor kopii, znajduje się tutaj fredosaurus.com/notes-cpp/oop-condestructors/… przypadek trzech dopasowań; zignoruj ​​nowego operatora, który służy jedynie jednoznacznemu stworzeniu.
Lorenzo Boccaccia
0
import java.io.IOException;

class Super {

    protected Super getClassName(Super s) throws IOException {
        System.out.println(this.getClass().getSimpleName() + " - I'm parent");
        return null;
    }

}

class SubOne extends Super {

    @Override
    protected Super getClassName(Super s)  {
        System.out.println(this.getClass().getSimpleName() + " - I'm Perfect Overriding");
        return null;
    }

}

class SubTwo extends Super {

    @Override
    protected Super getClassName(Super s) throws NullPointerException {
        System.out.println(this.getClass().getSimpleName() + " - I'm Overriding and Throwing Runtime Exception");
        return null;
    }

}

class SubThree extends Super {

    @Override
    protected SubThree getClassName(Super s) {
        System.out.println(this.getClass().getSimpleName()+ " - I'm Overriding and Returning SubClass Type");
        return null;
    }

}

class SubFour extends Super {

    @Override
    protected Super getClassName(Super s) throws IOException {
        System.out.println(this.getClass().getSimpleName()+ " - I'm Overriding and Throwing Narrower Exception ");
        return null;
    }

}

class SubFive extends Super {

    @Override
    public Super getClassName(Super s) {
        System.out.println(this.getClass().getSimpleName()+ " - I'm Overriding and have broader Access ");
        return null;
    }

}

class SubSix extends Super {

    public Super getClassName(Super s, String ol) {
        System.out.println(this.getClass().getSimpleName()+ " - I'm Perfect Overloading ");
        return null;
    }

}

class SubSeven extends Super {

    public Super getClassName(SubSeven s) {
        System.out.println(this.getClass().getSimpleName()+ " - I'm Perfect Overloading because Method signature (Argument) changed.");
        return null;
    }

}

public class Test{

    public static void main(String[] args) throws Exception {

        System.out.println("Overriding\n");

        Super s1 = new SubOne(); s1.getClassName(null);

        Super s2 = new SubTwo(); s2.getClassName(null);

        Super s3 = new SubThree(); s3.getClassName(null);

        Super s4 = new SubFour(); s4.getClassName(null);

        Super s5 = new SubFive(); s5.getClassName(null);

        System.out.println("Overloading\n");

        SubSix s6 = new SubSix(); s6.getClassName(null, null);

        s6 = new SubSix(); s6.getClassName(null);

        SubSeven s7 = new SubSeven(); s7.getClassName(s7);

        s7 = new SubSeven(); s7.getClassName(new Super());

    }
}
bharanitharan
źródło