Programavimas

Polimorfizmas ir paveldėjimas Java

Pasak legendos Venkat Subramaniam, polimorfizmas yra svarbiausia objektinio programavimo sąvoka. Polimorfizmas- arba objekto galimybė atlikti specializuotus veiksmus pagal jo tipą - tai daro „Java“ kodą lankstų. Dizaino modeliuose, tokiuose kaip „Command“, „Observer“, „Decorator“, „Strategy“ ir daugelis kitų, kuriuos sukūrė „Keturių gauja“, naudojami tam tikros formos polimorfizmas. Įvaldžius šią koncepciją labai pagerėja jūsų sugebėjimas apgalvoti programavimo iššūkių sprendimus.

Gaukite kodą

Galite gauti šio iššūkio šaltinio kodą ir atlikti savo bandymus čia: //github.com/rafadelnero/javaworld-challengers

Sąsajos ir paveldėjimas polimorfizme

Su šiuo „Java Challenger“ sutelkėme dėmesį į polimorfizmo ir paveldėjimo santykį. Svarbiausia nepamiršti, kad polimorfizmas reikalauja paveldėjimas ar sąsajos įgyvendinimas. Tai galite pamatyti žemiau pateiktame pavyzdyje, kuriame yra Duke ir Juggy:

 public abstract class JavaMascot {public abstract void executeAction (); } public class Duke praplečia JavaMascot {@Override public void executeAction () {System.out.println ("Punch!"); }} public class Juggy praplečia „JavaMascot“ {@Override public void executeAction () {System.out.println ("Fly!"); }} public class JavaMascotTest {public static void main (String ... args) {JavaMascot dukeMascot = new Duke (); „JavaMascot juggyMascot“ = naujas „Juggy“ (); dukeMascot.executeAction (); juggyMascot.executeAction (); }} 

Šio kodo išvestis bus:

 Punch! Skristi! 

Dėl jų specifinio įgyvendinimo abu Kunigaikštis ir JuggyVeiksmai bus įvykdyti.

Ar metodas perkrauna polimorfizmą?

Daugelis programuotojų yra supainioti dėl polimorfizmo santykio su metodo viršijimu ir metodo perkrova. Tiesą sakant, tikrasis polimorfizmas yra tik svarbiausias metodas. Perkrovimas turi tą patį metodo pavadinimą, tačiau parametrai skiriasi. Polimorfizmas yra platus terminas, todėl šia tema visada bus diskusijų.

Koks polimorfizmo tikslas?

Didelis polimorfizmo naudojimo pranašumas ir tikslas yra atsieti kliento klasę nuo diegimo kodo. Užuot kodavusi, kliento klasė gauna diegimą reikalingiems veiksmams atlikti. Tokiu būdu kliento klasė žino pakankamai, kad galėtų atlikti savo veiksmus, o tai yra laisvo ryšio pavyzdys.

Norėdami geriau suprasti polimorfizmo paskirtį, pažvelkite į „SweetCreator“:

 public abstract class „SweetProducer“ {public abstract void producSweet (); } public class CakeProducer praplečia SweetProducer {@Override public void producSweet () {System.out.println ("Pagamintas pyragas"); }} public class ChocolateProducer praplečia SweetProducer {@Override public void producSweet () {System.out.println ("Šokoladas pagamintas"); }} public class CookieProducer praplečia SweetProducer {@Override public void producSweet () {System.out.println ("Pagamintas slapukas"); }} public class SweetCreator {private List sweetProducer; viešasis „SweetCreator“ („sweetProducer“ sąrašas) {this.sweetProducer = sweetProducer; } public void createSweets () {sweetProducer.forEach (sweet -> sweet.produceSweet ()); }} public class SweetCreatorTest {public static void main (String ... args) {SweetCreator sweetCreator = new SweetCreator (Arrays.asList (new CakeProducer (), new ChocolateProducer (), new CookieProducer ())); sweetCreator.createSweets (); }} 

Šiame pavyzdyje galite pamatyti, kad „SweetCreator“ klasė žino tik  „SweetProducer“ klasė. Tai nežino kiekvieno iš jų įgyvendinimo Saldu. Šis atskyrimas suteikia mums lankstumo atnaujinti ir pakartotinai naudoti savo klases, ir tai žymiai palengvina kodo priežiūrą. Kurdami kodą, visada ieškokite būdų, kaip padaryti jį kuo lankstesnį ir prižiūrimą. polimorfizmas yra labai galinga technika, naudojama šiems tikslams.

Patarimas: @ Nepaisyti anotacija įpareigoja programuotoją naudoti tą patį metodo parašą, kuris turi būti nepaisomas. Jei metodas nepaisomas, bus kompiliavimo klaida.

Kovariantiniai grąžos tipai svarbesniu už metodą

Galima pakeisti nepaisomo metodo grąžinimo tipą, jei jis yra kovariantinis. A kovariančio tipo iš esmės yra grąžinimo tipo poklasis. Apsvarstykite pavyzdį:

 viešoji abstrakti klasė JavaMascot {abstraktus JavaMascot getMascot (); } public class Duke praplečia JavaMascot {@Orride Duke getMascot () {return new Duke (); }} 

Nes Kunigaikštis yra „JavaMascot“, mes galime pakeisti grąžinimo tipą nepaisydami.

Polimorfizmas su pagrindinėmis „Java“ klasėmis

Pagrindinėse „Java“ klasėse visą laiką naudojame polimorfizmą. Vienas labai paprastas pavyzdys yra tada, kai mes išaiškiname „ArrayList“ klasė, deklaruojantiSąrašas sąsaja kaip tipas:

 Sąrašo sąrašas = naujas „ArrayList“ (); 

Jei norite eiti toliau, apsvarstykite šį kodo pavyzdį naudodami „Java Collections“ API be polimorfizmas:

 public class ListActionWithoutPolymorphism {// Pavyzdys be polimorfizmo void executeVectorActions (Vector vector) {/ * Kodo kartojimas čia * /} void executeArrayListActions (ArrayList arrayList) {/ * Kodo pasikartojimas čia * /} void executeLinkedListActions * LinkedList čia * /} void executeCopyOnWriteArrayListActions (CopyOnWriteArrayList copyOnWriteArrayList) {/ * Kodo pakartojimas čia * /}} public class ListActionInvokerWithoutPolymorphism {listAction.executeVectorActions (naujas vektorius ()); listAction.executeArrayListActions (naujas ArrayList ()); listAction.executeLinkedListActions (naujas „LinkedList ()“); listAction.executeCopyOnWriteArrayListActions (naujas CopyOnWriteArrayList ()); } 

Bjaurus kodas, ar ne? Įsivaizduokite, kaip bandote tai išlaikyti! Dabar pažvelk į tą patį pavyzdį su polimorfizmas:

 public static void main (String… polymorphism) {ListAction listAction = new ListAction (); listAction.executeListActions (); } public class ListAction {void executeListActions (List list) {// Vykdyti veiksmus su skirtingais sąrašais}} public class ListActionInvoker {public static void main (String ... masterPolymorphism) {ListAction listAction = new ListAction (); listAction.executeListActions (naujas vektorius ()); listAction.executeListActions (naujas ArrayList ()); listAction.executeListActions (naujas „LinkedList ()“); listAction.executeListActions (naujas CopyOnWriteArrayList ()); }} 

Polimorfizmo nauda yra lankstumas ir išplėtimas. Užuot sukūrę kelis skirtingus metodus, galime deklaruoti tik vieną metodą, kuris gauna bendrąjį Sąrašas tipo.

Konkrečių metodų iškvietimas polimorfiniame metodo iškvietime

Polimorfiniame skambutyje galima pasinaudoti konkrečiais metodais, tačiau tai daroma lankstumo kaina. Štai pavyzdys:

 public abstract class MetalGearCharacter {abstract void useWeapon (Styginių ginklas); } viešosios klasės „BigBoss“ praplečia „MetalGearCharacter“ {@Override void useWeapon (String ginklas) {System.out.println („Big Boss naudoja„ + ginklą); } void giveOrderToTheArmy (String orderMessage) {System.out.println (orderMessage); }} viešosios klasės „SolidSnake“ praplečia „MetalGearCharacter“ {void useWeapon (String ginklas) {System.out.println („Solid Snake naudoja„ + “ginklą); }} public class UseSpecificMethod {public static void executeActionWith (MetalGearCharacter metalGearCharacter) {metalGearCharacter.useWeapon ("SOCOM"); // Žemiau esanti eilutė neveiks // metalGearCharacter.giveOrderToTheArmy ("Ataka!"); if („BigBoss“ metalGearCharacter egzempliorius) {((BigBoss) metalGearCharacter) .giveOrderToTheArmy („Ataka!“); }} public static void main (String ... specificPolymorphismInvocation) {executeActionWith (new SolidSnake ()); executeActionWith (naujas „BigBoss“); }} 

Technika, kurią mes čia naudojame liejimasarba sąmoningai keičiant objekto tipą vykdymo metu.

Atminkite, kad galima pasinaudoti konkrečiu metodu tik metant bendrąjį tipą į konkretų tipą. Gera analogija būtų aiškiai pasakyti kompiliatoriui: „Ei, aš žinau, ką aš čia darau, todėl ketinu perduoti objektą tam tikram tipui ir naudoti konkretų metodą“.

Remiantis aukščiau pateiktu pavyzdžiu, yra svarbi priežastis, dėl kurios kompiliatorius atsisako priimti konkretų metodo iškvietimą: perduodama klasė gali būti „SolidSnake“. Tokiu atveju kompiliatorius niekaip negali užtikrinti kiekvieno subklasės „MetalGearCharacter“ turi giveOrderToTheArmy deklaruotas metodas.

egzempliorius rezervuotas raktinis žodis

Atkreipkite dėmesį į rezervuotą žodį egzempliorius. Prieš pasitelkdami konkretų metodą, mes paklausėme, ar „MetalGearCharacter“ yra „egzempliorius„BigBoss“. Jei tai nebuvo a „BigBoss“ Pavyzdžiui, mes gausime šį išimties pranešimą:

 Išimtis temoje „main“ java.lang.ClassCastException: com.javaworld.javachallengers.polymorphism.specificinvocation.SolidSnake negalima perduoti į com.javaworld.javachallengers.polymorphism.specificinvocation.BigBoss 

super rezervuotas raktinis žodis

Ką daryti, jei norėtume nurodyti „Java“ superklasės atributą ar metodą? Šiuo atveju mes galėtume naudoti super rezervuotas žodis. Pavyzdžiui:

 viešosios klasės „JavaMascot“ {void executeAction () {System.out.println („„ Java “talismanas ketina atlikti veiksmą!“); }} public class Duke pratęsia JavaMascot {@Override void executeAction () {super.executeAction (); System.out.println ("Kunigaikštis mušis!"); } public static void main (String ... superReservedWord) {new Duke (). executeAction (); }} 

Naudojant rezervuotą žodį super į Kunigaikštis’S vykdyti veiksmą metodas naudoja superklasės metodą. Tada mes atliekame konkretų veiksmą Kunigaikštis. Štai kodėl abu pranešimus galime matyti išvesties apačioje:

 „Java“ talismanas ketina atlikti veiksmą! Kunigaikštis ims mušti! 

Priimkite polimorfizmo iššūkį!

Išbandykime, ką sužinojote apie polimorfizmą ir paveldėjimą. Šiame iššūkyje jums suteikta keletas metodų iš Matto Groeningo „Simpsonų“ ir jūsų užduotis yra išsiaiškinti, koks bus kiekvienos klasės rezultatas. Norėdami pradėti, atidžiai išanalizuokite šį kodą:

 public class PolymorphismChallenge {static abstract class Simpson {void talk () {System.out.println ("Simpsonas!"); } apsaugotas niekinis išdaiga (String prank) {System.out.println (išdaiga); }} statinė klasė Bartas pratęsia Simpsoną {String prank; Bartas (styginių išdaiga) {this.prank = išdaiga; } protected void talk () {System.out.println ("Valgyk mano šortus!"); } apsaugota tuštuma išdaiga () {super.prank (išdaiga); System.out.println („Numuškite Homerą“); }} statinė klasė Lisa pratęsia Simpsoną {void talk (String toMe) {System.out.println ("Aš myliu Saxą!"); }} public static void main (String ... doYourBest) {new Lisa (). talk ("Sax :)"); Simpsonas simpsonas = naujasis Bartas ("D'oh"); simpson.talk (); Lisa lisa = nauja Lisa (); lisa.talk (); ((Bartas) simpsonas) .prank (); }} 

Ką tu manai? Koks bus galutinis rezultatas? Nenaudokite IDE, kad tai išsiaiškintumėte! Esmė yra tobulinti savo kodo analizės įgūdžius, todėl pabandykite nustatyti išvestį patys.

Pasirinkite savo atsakymą ir toliau rasite teisingą atsakymą.

 A) Aš myliu „Sax“! D'oh Simpson! D'oh B) Sax :) Valgyk mano šortus! Aš myliu Saksą! D'oh Knock Homer down C) Sax :) D'oh Simpson! Numuškite Homerą D) Aš myliu Saksą! Valgyk mano šortus! Simpsonas! D'ohas nokautuos Homerą 

Kas ką tik nutiko? Polimorfizmo supratimas

Norėdami iškviesti šį metodą:

 nauja Liza (). pokalbis ("Saksas :)"); 

išvestis bus „Aš myliu Saksą!„Taip yra todėl, kad mes praeiname a Stygos prie metodo ir Liza turi metodą.

Kitam iškvietimui:

 Simpsonas simpsonas = naujasis Bartas ("D'oh");

simpson.talk ();

Išvestis busValgyk mano šortus!"Taip yra todėl, kad mes atliekame Simpsonas tipo su Bartas.

Dabar patikrinkite šį, kuris yra šiek tiek sudėtingesnis:

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

Čia mes naudojame metodo perkėlimą paveldėjimu. Mes nieko neperduodame pokalbio metodui, todėl Simpsonas kalbėti metodas. Tokiu atveju išvestis bus:

 - Simpson! 

Štai dar vienas:

 ((Bart) simpson) .prank (); 

Šiuo atveju išdaiga Stygos buvo priimtas, kai mes išaiškinome Bartas klasė su naujasis Bartas („D'oh“);. Šiuo atveju pirmiausia super.prankas bus naudojamas metodas, po kurio bus pateiktas konkretus išdaiga metodas nuo Bartas. Rezultatas bus:

 „D'oh“ „Numuškite Homerą“ 

Vaizdo iššūkis! Java polimorfizmo ir paveldėjimo derinimas

Derinimas yra vienas iš paprasčiausių būdų visiškai įsisavinti programavimo koncepcijas, kartu tobulinant kodą. Šiame vaizdo įraše galite sekti, kol aš derinu ir paaiškinu „Java“ polimorfizmo iššūkį:

Dažniausios polimorfizmo klaidos

Dažna klaida manyti, kad įmanoma pasinaudoti konkrečiu metodu nenaudojant liejimo.

Kita klaida - nežinia, koks metodas bus naudojamas, kai polimorfiškai klasifikuojama klasė. Atminkite, kad metodas, į kurį reikia kreiptis, yra sukurto egzemplioriaus metodas.

Taip pat atminkite, kad metodo nepaisymas nėra metodo perkrova.

Neįmanoma nepaisyti metodo, jei parametrai skiriasi. Tai yra įmanoma pakeisti nepaisomo metodo grąžinimo tipą, jei grąžinimo tipas yra superklasės metodo poklasis.

Ką prisiminti apie polimorfizmą

  • Sukurtas egzempliorius nustatys, koks metodas bus naudojamas naudojant polimorfizmą.
  • @ Nepaisyti anotacija įpareigoja programuotoją naudoti nepaisomą metodą; jei ne, bus kompiliatoriaus klaida.
  • Polimorfizmas gali būti naudojamas su įprastomis klasėmis, abstrakčiomis klasėmis ir sąsajomis.
  • Dauguma dizaino modelių priklauso nuo tam tikros polimorfizmo formos.
  • Vienintelis būdas naudoti konkretų metodą polimorfiniame poklasyje yra liejimas.
  • Naudodami polimorfizmą, galite sukurti galingą savo kodo struktūrą.
  • Atlikite testus. Tai padarę galėsite įsisavinti šią galingą koncepciją!

Atsakymo raktas

Atsakymas į šį „Java“ varžovą yra D. Rezultatas būtų:

 Aš myliu Saksą! Valgyk mano šortus! Simpsonas! D'ohas nokautuos Homerą 

Šią istoriją „Polimorfizmas ir paveldėjimas Java“ iš pradžių paskelbė „JavaWorld“.

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