JavaRush /Java Blog /Random-TL /Polymorphism sa Java

Polymorphism sa Java

Nai-publish sa grupo
Ang mga tanong tungkol sa OOP ay isang mahalagang bahagi ng isang teknikal na panayam para sa posisyon ng isang developer ng Java sa isang kumpanya ng IT. Sa artikulong ito ay pag-uusapan natin ang tungkol sa isa sa mga prinsipyo ng OOP - polymorphism. Kami ay tumutuon sa mga aspeto na madalas itanong sa panahon ng mga panayam, at magbibigay din ng maliliit na halimbawa para sa kalinawan.

Ano ang polymorphism?

Ang polymorphism ay ang kakayahan ng isang programa na magkaparehong gumamit ng mga bagay na may parehong interface nang walang impormasyon tungkol sa partikular na uri ng bagay na ito. Kung sasagutin mo ang tanong kung ano ang polymorphism sa ganitong paraan, malamang na hihilingin sa iyo na ipaliwanag kung ano ang ibig mong sabihin. Muli, nang hindi humihingi ng isang grupo ng mga karagdagang katanungan, ilagay ang lahat sa pagkakasunud-sunod para sa tagapanayam.

Polymorphism sa Java sa isang panayam - 1
Maaari tayong magsimula sa katotohanan na ang diskarte sa OOP ay nagsasangkot ng pagbuo ng isang Java program batay sa pakikipag-ugnayan ng mga bagay na batay sa mga klase. Ang mga klase ay mga pre-written na mga guhit (mga template) ayon sa kung aling mga bagay sa programa ang gagawin. Bukod dito, ang isang klase ay palaging may isang tiyak na uri, na, na may isang mahusay na istilo ng programming, "sinasabi" ang layunin nito sa pamamagitan ng pangalan nito. Dagdag pa, mapapansin na dahil ang Java ay isang malakas na na-type na wika, ang program code ay palaging kailangang ipahiwatig ang uri ng bagay kapag nagdedeklara ng mga variable. Idagdag dito na ang mahigpit na pagta-type ay nagpapataas ng kaligtasan ng code at pagiging maaasahan ng programa at nagbibigay-daan sa iyong maiwasan ang mga error sa hindi pagkakatugma ng uri (halimbawa, isang pagtatangka na hatiin ang isang string sa isang numero) sa yugto ng pag-compile. Naturally, ang compiler ay dapat "alam" ang ipinahayag na uri - ito ay maaaring isang klase mula sa JDK o isa na nilikha namin mismo. Pakitandaan sa tagapanayam na kapag nagtatrabaho sa code ng programa, maaari naming gamitin hindi lamang ang mga bagay ng uri na itinalaga namin kapag nagdedeklara, kundi pati na rin ang mga inapo nito. Ito ay isang mahalagang punto: maaari nating tratuhin ang maraming uri na parang isa lamang sila (hangga't ang mga uri na iyon ay hango sa isang batayang uri). Nangangahulugan din ito na, sa pagdeklara ng variable ng isang uri ng superclass, maaari nating italaga dito ang halaga ng isa sa mga inapo nito. Magugustuhan ito ng tagapanayam kung magbibigay ka ng halimbawa. Pumili ng ilang bagay na maaaring karaniwan (base) para sa isang pangkat ng mga bagay at magmana ng ilang klase mula dito. Batayang klase:
public class Dancer {
    private String name;
    private int age;

    public Dancer(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void dance() {
        System.out.println(toString() + "I dance like everyone else.");
    }

    @Override
    public String toString() {
        return "Я " + name + ", to me " + age + " years. " ;
    }
}
Sa mga inapo, i-override ang base class method:
public class ElectricBoogieDancer extends Dancer {
    public ElectricBoogieDancer(String name, int age) {
        super(name, age);
    }
// overriding the base class method
    @Override
    public void dance() {
        System.out.println( toString() + "I dance electric boogie!");
    }
}

public class BreakDankDancer extends Dancer{

    public BreakDankDancer(String name, int age) {
        super(name, age);
    }
// overriding the base class method
    @Override
    public void dance(){
        System.out.println(toString() + "I'm breakdancing!");
    }
}
Isang halimbawa ng polymorphism sa Java at ang paggamit ng mga bagay sa isang programa:
public class Main {

    public static void main(String[] args) {
        Dancer dancer = new Dancer("Anton", 18);

        Dancer breakDanceDancer = new BreakDankDancer("Alexei", 19);// upcast to base type
        Dancer electricBoogieDancer = new ElectricBoogieDancer("Igor", 20); // upcast to base type

        List<Dancer> discotheque = Arrays.asList(dancer, breakDanceDancer, electricBoogieDancer);
        for (Dancer d : discotheque) {
            d.dance();// polymorphic method call
        }
    }
}
mainIpakita sa code ng pamamaraan kung ano ang nasa mga linya:
Dancer breakDanceDancer = new BreakDankDancer("Alexei", 19);
Dancer electricBoogieDancer = new ElectricBoogieDancer("Igor", 20);
Nagdeklara kami ng isang superclass na uri ng variable at itinalaga ito ng halaga ng isa sa mga inapo. Malamang, tatanungin ka kung bakit hindi magrereklamo ang compiler tungkol sa hindi pagkakatugma sa pagitan ng mga uri na ipinahayag sa kaliwa at sa kanan ng tanda ng pagtatalaga, dahil ang Java ay may mahigpit na pag-type. Ipaliwanag na ang paitaas na uri ng conversion ay gumagana dito - ang isang reference sa isang bagay ay binibigyang kahulugan bilang isang reference sa base class. Bukod dito, ang compiler, na nakatagpo ng ganitong konstruksiyon sa code, ay ginagawa ito nang awtomatiko at implicitly. Batay sa halimbawang code, maipapakita na ang uri ng klase na idineklara sa kaliwa ng tanda ng pagtatalaga Danceray may ilang mga form (mga uri) na ipinahayag sa kanan BreakDankDancer, ElectricBoogieDancer. Ang bawat isa sa mga form ay maaaring magkaroon ng sarili nitong natatanging gawi para sa karaniwang paggana na tinukoy sa superclass - method dance. Iyon ay, ang isang paraan na idineklara sa isang superclass ay maaaring ipatupad nang iba sa mga inapo nito. Sa kasong ito, kami ay nakikitungo sa paraan ng overriding, at ito ay eksakto kung ano ang lumilikha ng iba't ibang mga anyo (pag-uugali). Maaari mong makita ito sa pamamagitan ng pagpapatakbo ng pangunahing code ng pamamaraan para sa pagpapatupad: Output ng programa Ako si Anton, ako ay 18 taong gulang. Sumasayaw ako tulad ng iba. Ako si Alexey, 19 taong gulang ako. Breakdance ko! Ako si Igor, 20 taong gulang ako. Sumasayaw ako ng electric boogie! Kung hindi tayo gumamit ng overriding sa mga inapo, hindi tayo magkakaroon ng ibang pag-uugali. Halimbawa, kung magkomento BreakDankDancerkami ng paraan para sa aming mga klase , ang output ng programa ay magiging ganito: Ako si Anton, ako ay 18 taong gulang. Sumasayaw ako tulad ng iba. Ako si Alexey, 19 taong gulang ako. Sumasayaw ako tulad ng iba. Ako si Igor, 20 taong gulang ako. Sumasayaw ako tulad ng iba. at nangangahulugan ito na walang saysay ang paglikha ng mga bagong klase . Ano, eksakto, ang prinsipyo ng Java polymorphism? Saan nakatago ang paggamit ng isang bagay sa isang programa nang hindi nalalaman ang partikular na uri nito? Sa aming halimbawa, ito ay isang method call sa isang object ng uri . Java polymorphism ay nangangahulugan na ang programa ay hindi kailangang malaman kung anong uri ang bagay o bagay ay magiging . Ang pangunahing bagay ay na ito ay isang inapo ng klase . At kung pinag-uusapan natin ang tungkol sa mga inapo, dapat tandaan na ang mana sa Java ay hindi lamang , kundi pati na rin . Ngayon na ang oras upang tandaan na hindi sinusuportahan ng Java ang maramihang pamana - ang bawat uri ay maaaring magkaroon ng isang magulang (superclass) at walang limitasyong bilang ng mga inapo (subclasses). Samakatuwid, ang mga interface ay ginagamit upang magdagdag ng maramihang pag-andar sa mga klase. Binabawasan ng mga interface ang pagkakabit ng mga bagay sa isang magulang kumpara sa pamana at napakalawak na ginagamit. Sa Java, ang isang interface ay isang uri ng sanggunian, kaya maaaring ideklara ng isang programa ang uri bilang isang variable ng uri ng interface. Ito ay isang magandang panahon upang magbigay ng isang halimbawa. Gumawa tayo ng interface: ElectricBoogieDancerdanceBreakDankDancerElectricBoogieDancerd.dance()dDancerBreakDankDancerElectricBoogieDancerDancerextendsimplements
public interface Swim {
    void swim();
}
Para sa kalinawan, kumuha tayo ng iba't ibang at hindi nauugnay na mga bagay at magpatupad ng isang interface sa kanila:
public class Human implements Swim {
    private String name;
    private int age;

    public Human(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public void swim() {
        System.out.println(toString()+"I swim with an inflatable ring.");
    }

    @Override
    public String toString() {
        return "Я " + name + ", to me " + age + " years. ";
    }

}

public class Fish implements Swim{
    private String name;

    public Fish(String name) {
        this.name = name;
    }

    @Override
    public void swim() {
        System.out.println("I'm a fish " + name + ". I swim by moving my fins.");

    }

public class UBoat implements Swim {

    private int speed;

    public UBoat(int speed) {
        this.speed = speed;
    }

    @Override
    public void swim() {
        System.out.println("The submarine is sailing, rotating the propellers, at a speed" + speed + " knots.");
    }
}
Paraan main:
public class Main {

    public static void main(String[] args) {
        Swim human = new Human("Anton", 6);
        Swim fish = new Fish("whale");
        Swim boat = new UBoat(25);

        List<Swim> swimmers = Arrays.asList(human, fish, boat);
        for (Swim s : swimmers) {
            s.swim();
        }
    }
}
Ang resulta ng pagsasagawa ng polymorphic na pamamaraan na tinukoy sa isang interface ay nagbibigay-daan sa amin na makita ang mga pagkakaiba sa pag-uugali ng mga uri na nagpapatupad ng interface na iyon. Binubuo ang mga ito sa iba't ibang resulta ng pagpapatupad ng pamamaraan swim. Pagkatapos pag-aralan ang aming halimbawa, maaaring magtanong ang tagapanayam kung bakit, kapag ipinatupad ang code mula samain
for (Swim s : swimmers) {
            s.swim();
}
Ang mga pamamaraan ba na tinukoy sa mga klase na ito ay tinatawag para sa aming mga bagay? Paano mo pipiliin ang nais na pagpapatupad ng isang pamamaraan kapag nagpapatupad ng isang programa? Upang masagot ang mga tanong na ito, kailangan nating pag-usapan ang tungkol sa huli (dynamic) na pagbubuklod. Sa pamamagitan ng pagbubuklod, ang ibig naming sabihin ay pagtatatag ng koneksyon sa pagitan ng isang tawag sa pamamaraan at ang partikular na pagpapatupad nito sa mga klase. Sa esensya, tinutukoy ng code kung alin sa tatlong pamamaraan na tinukoy sa mga klase ang isasagawa. Ang Java bilang default ay gumagamit ng late binding (sa runtime sa halip na sa compile time, gaya ng kaso sa early binding). Nangangahulugan ito na kapag kino-compile ang code
for (Swim s : swimmers) {
            s.swim();
}
hindi pa alam ng compiler kung aling klase ang code ay mula sa Human, Fisho kung Uboatito ay isasagawa sa swim. Ito ay matutukoy lamang kapag ang programa ay naisakatuparan salamat sa mekanismo ng dynamic na pagpapadala - pagsuri sa uri ng bagay sa panahon ng pagpapatupad ng programa at pagpili ng nais na pagpapatupad ng pamamaraan para sa ganitong uri. Kung tatanungin ka kung paano ito ipinatupad, masasagot mo na kapag naglo-load at nag-initialize ng mga bagay, ang JVM ay bumubuo ng mga talahanayan sa memorya, at sa mga ito ay iniuugnay ang mga variable sa kanilang mga halaga, at mga bagay sa kanilang mga pamamaraan. Bukod dito, kung ang isang bagay ay minana o nagpapatupad ng isang interface, ang pagkakaroon ng mga overridden na pamamaraan sa klase nito ay unang susuriin. Kung mayroon man, nakatali ang mga ito sa ganitong uri, kung hindi, hahanapin ang isang pamamaraan na tinukoy sa klase na isang antas na mas mataas (sa magulang) at iba pa hanggang sa ugat sa isang multi-level na hierarchy. Sa pagsasalita tungkol sa polymorphism sa OOP at sa pagpapatupad nito sa program code, tandaan namin na magandang kasanayan ang paggamit ng abstract na paglalarawan upang tukuyin ang mga base class gamit ang abstract classes pati na rin ang mga interface. Ang kasanayang ito ay batay sa paggamit ng abstraction - pagbubukod ng karaniwang pag-uugali at pag-aari at pagsasama sa mga ito sa loob ng abstract na klase, o pagbubukod lamang ng karaniwang pag-uugali - kung saan lumikha kami ng isang interface. Ang pagbuo at pagdidisenyo ng hierarchy ng mga bagay batay sa mga interface at class inheritance ay isang kinakailangan para sa pagtupad sa prinsipyo ng OOP polymorphism. Tungkol sa isyu ng polymorphism at inobasyon sa Java, maaari nating banggitin na kapag lumilikha ng mga abstract na klase at interface, simula sa Java 8, posibleng magsulat ng default na pagpapatupad ng mga abstract na pamamaraan sa mga batayang klase gamit ang keyword default. Halimbawa:
public interface Swim {
    default void swim() {
        System.out.println("Just floating");
    }
}
Minsan maaari silang magtanong tungkol sa mga kinakailangan para sa pagdedeklara ng mga pamamaraan sa mga batayang klase upang ang prinsipyo ng polymorphism ay hindi nilabag. Ang lahat ay simple dito: ang mga pamamaraang ito ay hindi dapat static , pribado at pangwakas . Ginagawang available lang ng Pribado ang pamamaraan sa klase, at hindi mo ito ma-override sa descendant. Ginagawa ng static na pag-aari ng klase ang pamamaraan, hindi ang object, kaya palaging tatawagin ang superclass na pamamaraan. Ang pangwakas ay gagawing hindi nababago at nakatago sa mga tagapagmana nito.

Ano ang ibinibigay sa atin ng polymorphism sa Java?

Ang tanong kung ano ang ibinibigay sa atin ng paggamit ng polymorphism ay malamang na babangon din. Dito maaari kang sumagot nang maikli, nang hindi masyadong malalim sa mga damo:
  1. Binibigyang-daan kang palitan ang mga pagpapatupad ng object. Ito ang batayan ng pagsubok.
  2. Nagbibigay ng pagpapalawak ng programa - nagiging mas madali ang paglikha ng pundasyon para sa hinaharap. Ang pagdaragdag ng mga bagong uri batay sa mga umiiral na ay ang pinakakaraniwang paraan upang palawakin ang functionality ng mga program na nakasulat sa istilong OOP.
  3. Binibigyang-daan kang pagsamahin ang mga bagay na may karaniwang uri o gawi sa isang koleksyon o hanay at manipulahin ang mga ito nang pantay-pantay (tulad ng sa aming mga halimbawa, ginagawang sumayaw ang lahat - isang paraan danceo lumangoy - isang pamamaraan swim).
  4. Kakayahang umangkop kapag gumagawa ng mga bagong uri: maaari mong piliing ipatupad ang isang paraan mula sa isang magulang o i-override ito sa isang bata.

Mga salitang naghihiwalay para sa paglalakbay

Ang prinsipyo ng polymorphism ay isang napakahalaga at malawak na paksa. Sinasaklaw nito ang halos kalahati ng OOP ng Java at isang magandang bahagi ng mga pangunahing kaalaman ng wika. Hindi ka makakatakas sa pagtukoy sa prinsipyong ito sa isang panayam. Ang kamangmangan o hindi pagkakaunawaan dito ay malamang na magtatapos sa panayam. Samakatuwid, huwag maging tamad na suriin ang iyong kaalaman bago ang pagsubok at i-refresh ito kung kinakailangan.
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION