Programiranje

Polimorfizem in dedovanje v Javi

Po legendi Venkat Subramaniam je polimorfizem najpomembnejši koncept v objektno usmerjenem programiranju. Polimorfizem- ali zmožnost predmeta, da izvaja specializirana dejanja glede na njegovo vrsto - je tisto, zaradi česar je koda Java prilagodljiva. Oblikovalski vzorci, kot so Command, Observer, Decorator, Strategy in mnogi drugi, ki jih je ustvarila skupina Gang Of Four, vsi uporabljajo neko obliko polimorfizma. Obvladovanje tega koncepta močno izboljša vašo sposobnost razmišljanja o rešitvah programskih izzivov.

Pridobite kodo

Izvorno kodo za ta izziv lahko dobite in zaženete lastne teste tukaj: //github.com/rafadelnero/javaworld-challengers

Vmesniki in dedovanje v polimorfizmu

S tem Java Challengerjem se osredotočamo na razmerje med polimorfizmom in dedovanjem. Upoštevati je treba predvsem to, da zahteva polimorfizem dedovanje ali izvedba vmesnika. To lahko vidite v spodnjem primeru z Dukeom in Juggyjem:

 javni abstraktni razred JavaMascot {public abstract void executeAction (); } javni razred Duke podaljša JavaMascot {@Override public void executeAction () {System.out.println ("Punch!"); }} javni razred Juggy razširja JavaMascot {@Override public void executeAction () {System.out.println ("Fly!"); }} javni razred JavaMascotTest {public static void main (String ... args) {JavaMascot dukeMascot = new Duke (); JavaMascot juggyMascot = novo Juggy (); dukeMascot.executeAction (); juggyMascot.executeAction (); }} 

Rezultat te kode bo:

 Punch! Leti! 

Zaradi svoje posebne izvedbe oboje vojvoda in JuggyIzvedena bodo dejanja.

Ali metoda preobremenjuje polimorfizem?

Mnogi programerji so zmedeni glede odnosa polimorfizma do preglasitve metode in preobremenitve metode. Pravzaprav je edina metoda, ki prevlada, pravi polimorfizem. Preobremenitev deli ime iste metode, vendar so parametri različni. Polimorfizem je širok pojem, zato se bodo o tej temi vedno razpravljale.

Kaj je namen polimorfizma?

Velika prednost in namen uporabe polimorfizma je ločiti odjemalski razred od izvedbene kode. Namesto da bi bil odjemalski razred trdo kodiran, prejme izvedbo za izvedbo potrebnega dejanja. Na ta način odjemalski razred ve le toliko, da lahko izvede svoja dejanja, kar je primer ohlapnega spenjanja.

Če želite bolje razumeti namen polimorfizma, si oglejte SweetCreator:

 javni abstraktni razred SweetProducer {javni povzetek void produceSweet (); } javni razred CakeProducer razširja SweetProducer {@Override public void produceSweet () {System.out.println ("Torta proizvedena"); }} javni razred ChocolateProducer razširja SweetProducer {@Override public void produceSweet () {System.out.println ("Pridelana čokolada"); }} javni razred CookieProducer razširja SweetProducer {@Override public void produceSweet () {System.out.println ("Piškotek proizveden"); }} javni razred SweetCreator {zasebni seznam sweetProducer; javni SweetCreator (seznam sweetProducer) {this.sweetProducer = sweetProducer; } javna praznina createSweets () {sweetProducer.forEach (sweet -> sweet.produceSweet ()); }} javni razred SweetCreatorTest {public static void main (String ... args) {SweetCreator sweetCreator = new SweetCreator (Arrays.asList (new CakeProducer (), new ChocolateProducer (), new CookieProducer ())); sweetCreator.createSweets (); }} 

V tem primeru lahko vidite, da je SweetCreator razred pozna samo  SweetProducer razred. Ne pozna izvedbe vsakega Sladko. Ta ločitev nam omogoča prilagodljivost pri posodabljanju in ponovni uporabi naših razredov, kodo pa je veliko lažje vzdrževati. Pri oblikovanju kode vedno iščite načine, kako jo narediti čim bolj prilagodljivo in vzdržno. polimorfizem je zelo močna tehnika za uporabo v te namene.

Nasvet: The @Override pripis obvezuje programerja, da uporabi isti podpis metode, ki ga je treba preglasiti. Če metoda ni razveljavljena, bo prišlo do napake pri prevajanju.

Kovariantne vrste vrnitve pri preglasitvi metode

Možno je spremeniti vrsto vrnitve razveljavljene metode, če gre za kovarianten tip. A kovarianten tip je v bistvu podrazred vrste return. Poglejmo primer:

 javni abstraktni razred JavaMascot {abstraktni JavaMascot getMascot (); } javni razred Duke razširja JavaMascot {@Override Duke getMascot () {vrni novega Duke (); }} 

Ker vojvoda je JavaMascot, lahko spremenimo vrsto vrnitve pri razveljavitvi.

Polimorfizem z osnovnimi razredi Java

V osnovnih razredih Java ves čas uporabljamo polimorfizem. Eden od zelo preprostih primerov je, ko ustvarimo primer ArrayList razred, ki razglasiSeznam vmesnik kot vrsta:

 Seznam seznamov = new ArrayList (); 

Če želite nadaljevati, si oglejte ta vzorec kode z API-jem Java Collections brez polimorfizem:

 javni razred ListActionWithoutPolymorphism {// Primer brez polimorfizma void executeVectorActions (vektor vektorja) {/ * ponovitev kode tukaj * /} void executeArrayListActions (ArrayList arrayList) {/ * ponovitev kode tukaj * /} void executeLinkedListActions (LinkedList linked Code repelltion) tukaj * /} void executeCopyOnWriteArrayListActions (CopyOnWriteArrayList copyOnWriteArrayList) {/ * Ponavljanje kode tukaj * /}} javni razred ListActionInvokerWithoutPolymorphism {listAction.executeVectorActions (nov vektor ()); listAction.executeArrayListActions (novo ArrayList ()); listAction.executeLinkedListActions (novo LinkedList ()); listAction.executeCopyOnWriteArrayListActions (novo CopyOnWriteArrayList ()); } 

Grda koda, kajne? Predstavljajte si, da ga poskušate vzdrževati! Zdaj si oglejte isti primer s polimorfizem:

 public static void main (String… polimorfizem) {ListAction listAction = new ListAction (); listAction.executeListActions (); } javni razred ListAction {void executeListActions (Seznam seznam) {// Izvajaj dejanja z različnimi seznami}} javni razred ListActionInvoker {javni statični void main (String ... masterPolymorphism) {ListAction listAction = new ListAction (); listAction.executeListActions (novo Vector ()); listAction.executeListActions (novo ArrayList ()); listAction.executeListActions (novo LinkedList ()); listAction.executeListActions (novo CopyOnWriteArrayList ()); }} 

Prednost polimorfizma je prilagodljivost in razširljivost. Namesto da ustvarimo več različnih metod, lahko razglasimo samo eno metodo, ki prejme generično Seznam tip.

Klicanje določenih metod v klicu polimorfne metode

V polimorfnem klicu se lahko sklicujete na določene metode, vendar to počne za ceno prilagodljivosti. Tu je primer:

 javni abstraktni razred MetalGearCharacter {abstract void useWeapon (String orožje); } javni razred BigBoss razširja MetalGearCharacter {@Override void useWeapon (String orožje) {System.out.println ("Big Boss uporablja orožje" +); } void giveOrderToTheArmy (String orderMessage) {System.out.println (orderMessage); }} javni razred SolidSnake razširja MetalGearCharacter {void useWeapon (String orožje) {System.out.println ("Solid Snake uporablja orožje" +); }} javni razred UseSpecificMethod {javna statična praznina executeActionWith (MetalGearCharacter metalGearCharacter) {metalGearCharacter.useWeapon ("SOCOM"); // Spodnja vrstica ne bi delovala // metalGearCharacter.giveOrderToTheArmy ("Napad!"); if (metalGearCharacter instanceof BigBoss) {((BigBoss) metalGearCharacter) .giveOrderToTheArmy ("Attack!"); }} javna statična void glavna (String ... specificPolymorphismInvocation) {executeActionWith (new SolidSnake ()); executeActionWith (novi BigBoss ()); }} 

Tehnika, ki jo uporabljamo tukaj, je litjeali namerno spreminjanje vrste predmeta med izvajanjem.

Upoštevajte, da je mogoče uporabiti določeno metodo samo pri predvajanju generičnega tipa na določeno vrsto. Dobra analogija bi bila, če bi prevajalniku izrecno rekli: "Hej, vem, kaj počnem tukaj, zato bom objekt predal na določeno vrsto in uporabil določeno metodo."

Glede na zgornji primer obstaja pomemben razlog, da prevajalnik noče sprejeti določenega klica metode: predani razred bi lahko bil SolidSnake. V tem primeru prevajalnik ne more zagotoviti vsakega podrazreda MetalGearCharacter ima giveOrderToTheArmy razglašena metoda.

The instanceof rezervirana ključna beseda

Bodite pozorni na rezervirano besedo instanceof. Preden začnemo uporabljati določeno metodo, smo vprašali, ali MetalGearCharacter je "instanceofVeliki šef. Če je ni bil a Veliki šef primer, bi prejeli naslednje sporočilo o izjemi:

 Izjeme v niti "main" java.lang.ClassCastException: com.javaworld.javachallengers.polymorphism.specificinvocation.SolidSnake ni mogoče oddati v com.javaworld.javachallengers.polymorphism.specificinvocation.BigBoss 

The super rezervirana ključna beseda

Kaj če bi se želeli sklicevati na atribut ali metodo iz superklase Java? V tem primeru bi lahko uporabili super pridržana beseda. Na primer:

 javni razred JavaMascot {void executeAction () {System.out.println ("Maskota Java bo kmalu izvedla dejanje!"); }} javni razred Duke razširi JavaMascot {@Override void executeAction () {super.executeAction (); System.out.println ("Duke bo udaril!"); } public static void main (String ... superReservedWord) {new Duke (). executeAction (); }} 

Uporaba pridržane besede super v vojvoda"s executeAction metoda prikliče metodo superklase. Nato izvedemo določeno dejanje iz vojvoda. Zato lahko v spodnjem izhodu vidimo obe sporočili:

 Maskota Java bo kmalu izvedla akcijo! Duke bo udaril! 

Sprejmite izziv polimorfizma!

Preizkusimo, kaj ste se naučili o polimorfizmu in dedovanju. V tem izzivu dobite nekaj metod iz filma The Simpsons Matta Groeninga in vaš izziv je ugotoviti, kakšen bo rezultat za vsak razred. Za začetek natančno analizirajte naslednjo kodo:

 javni razred PolymorphismChallenge {statični abstraktni razred Simpson {void talk () {System.out.println ("Simpson!"); } zaščitena neveljavna potegavščina (nizka potegavščina) {System.out.println (potegavščina); }} statični razred Bart razširja Simpsona {String potegavščina; Bart (nizka potegavščina) {this.prank = potegavščina; } zaščiten void talk () {System.out.println ("Jej moje kratke hlače!"); } zaščitena void potegavščina () {super.prank (potegavščina); System.out.println ("Knock Homer down"); }} statični razred Lisa razširja Simpsona {void talk (String toMe) {System.out.println ("I love Sax!"); }} public static void main (String ... doYourBest) {new Lisa (). talk ("Sax :)"); Simpson simpson = novi Bart ("D'oh"); simpson.talk (); Lisa lisa = nova Lisa (); lisa.talk (); ((Bart) simpson) .prank (); }} 

Kaj misliš? Kakšen bo končni rezultat? Ne uporabljajte IDE, da bi to ugotovili! Bistvo je izboljšati svoje sposobnosti analize kode, zato poskusite sami določiti rezultat.

Izberite svoj odgovor in spodaj boste našli pravilen odgovor.

 A) Obožujem Saxa! D'oh Simpson! D'oh B) Sax :) Pojej moje kratke hlače! Obožujem Saxa! D'oh Knock Homer dol C) Sax :) D'oh Simpson! Podreti Homerja D) Obožujem Saxa! Pojej moje kratke hlače! Simpson! D'oh, knock Homer dol 

Kaj se je pravkar zgodilo? Razumevanje polimorfizma

Za priklic naslednje metode:

 nova Lisa (). pogovor ("Sax :)"); 

izhod bo "Obožujem Saxa!”To je zato, ker gremo mimo Vrvica na metodo in Lisa ima metodo.

Za naslednji klic:

 Simpson simpson = novi Bart ("D'oh");

simpson.talk ();

Rezultat bo "Pojej moje kratke hlače!"To je zato, ker ustvarjamo primer Simpson tip z Bart.

Zdaj pa preverite to, ki je nekoliko bolj zapletena:

 Lisa lisa = nova Lisa (); lisa.talk (); 

Tu uporabljamo preobremenitev metode z dedovanjem. Metodi pogovora ne prenašamo ničesar, zato Simpson pogovor se prikliče metoda. V tem primeru bo rezultat:

 "Simpson!" 

Tu je še ena:

 ((Bart) simpson) .prank (); 

V tem primeru je potegavščina String je bil sprejet, ko smo ustvarili Bart razred s novi Bart ("D'oh");. V tem primeru najprej super.prank bo priklicana metoda, ki ji sledi posebna Šala metoda iz Bart. Rezultat bo:

 "D'oh" "Knock Homer down" 

Video izziv! Razhroščevanje polimorfizma in dedovanja Java

Odpravljanje napak je eden najlažjih načinov za popolno absorpcijo konceptov programiranja, hkrati pa izboljšate kodo. V tem videoposnetku lahko sledite, medtem ko razlagam in razložim izziv polimorfizma Java:

Pogoste napake pri polimorfizmu

Pogosta napaka je, če mislimo, da je mogoče uporabiti določeno metodo brez uporabe odlitka.

Druga napaka je v tem, da nismo prepričani, katera metoda bo uporabljena pri polimorfnem instanciranju razreda. Ne pozabite, da je metoda, ki jo je treba priklicati, metoda ustvarjenega primerka.

Ne pozabite tudi, da preglasitev metode ni preobremenitev metode.

Metode je nemogoče preglasiti, če so parametri drugačni. To mogoče za spremembo vrste vrnitve prepisane metode, če je vrsta vrnitve podrazred metode superrazreda.

Kaj si je treba zapomniti pri polimorfizmu

  • Ustvarjeni primerek bo določil, katera metoda bo uporabljena pri uporabi polimorfizma.
  • The @Override pripis obvezuje programerja, da uporabi nadomeščeno metodo; v nasprotnem primeru bo prišlo do napake prevajalnika.
  • Polimorfizem se lahko uporablja z običajnimi razredi, abstraktnimi razredi in vmesniki.
  • Večina vzorcev oblikovanja je odvisna od neke oblike polimorfizma.
  • Edini način za uporabo določene metode v vašem polimorfnem podrazredu je uporaba ulivanja.
  • Z uporabo polimorfizma lahko v svoji kodi oblikujete močno strukturo.
  • Zaženite svoje teste. S tem boste lahko obvladali ta močan koncept!

Tipka za odgovor

Odgovor na ta izzivalec Java je D. Rezultat bi bil:

 Obožujem Saxa! Pojej moje kratke hlače! Simpson! D'oh, knock Homer dol 

To zgodbo "Polimorfizem in dedovanje v Javi" je prvotno objavil JavaWorld.

$config[zx-auto] not found$config[zx-overlay] not found