Programovanie

Polymorfizmus a dedičnosť v Jave

Podľa legendy Venkat Subramaniam je polymorfizmus najdôležitejšou koncepciou v objektovo orientovanom programovaní. Polymorfizmus- alebo schopnosť objektu vykonávať špecializované akcie založené na jeho type - je to, čo robí kód Java flexibilným. Dizajnové vzory ako Command, Observer, Decorator, Strategy a mnoho ďalších vytvorené Gangom štyroch, všetky využívajú určitú formu polymorfizmu. Osvojenie tohto konceptu výrazne zlepšuje vašu schopnosť premýšľať nad riešeniami programových výziev.

Získajte kód

Zdrojový kód pre túto výzvu môžete získať a spustiť svoje vlastné testy tu: //github.com/rafadelnero/javaworld-challengers

Rozhrania a dedičnosť v polymorfizme

S týmto Java Challenger sa zameriavame na vzťah medzi polymorfizmom a dedičstvom. Hlavná vec, ktorú treba mať na pamäti, je, že polymorfizmus vyžaduje dedenie alebo implementácia rozhrania. Môžete to vidieť na príklade nižšie, kde sú predstavení Duke a Juggy:

 public abstract class JavaMascot {public abstract void executeAction (); } public class Duke extends JavaMascot {@Override public void executeAction () {System.out.println ("Punch!"); }} public class Juggy rozširuje JavaMascot {@Override public void executeAction () {System.out.println ("Fly!"); }} public class JavaMascotTest {public static void main (String ... args) {JavaMascot dukeMascot = new Duke (); JavaMascot juggyMascot = nový Juggy (); dukeMascot.executeAction (); juggyMascot.executeAction (); }} 

Výstup z tohto kódu bude:

 Punch! Leť! 

Z dôvodu ich konkrétnych implementácií obidve Vojvoda a JuggyAkcie sa vykonajú.

Preťažuje metóda polymorfizmus?

Mnoho programátorov je zmätených vo vzťahu polymorfizmu k prepisovaniu metód a preťažovaniu metód. Skutočný polymorfizmus je v skutočnosti iba prepísanie metódy. Preťaženie zdieľa rovnaký názov metódy, ale parametre sú odlišné. Polymorfizmus je široký pojem, takže o tejto téme budú vždy prebiehať diskusie.

Aký je účel polymorfizmu?

Veľkou výhodou a účelom použitia polymorfizmu je oddelenie triedy klienta od implementačného kódu. Namiesto toho, aby bola pevne zakódovaná, dostane trieda klienta implementáciu na vykonanie potrebnej akcie. Týmto spôsobom trieda klienta vie len toľko, aby mohla vykonávať svoje akcie, čo je príklad voľného spojenia.

Ak chcete lepšie pochopiť účel polymorfizmu, pozrite sa na SweetCreator:

 public abstract class SweetProducer {public abstract void produceSweet (); } public class CakeProducer extends SweetProducer {@Override public void produceSweet () {System.out.println ("Cake produced"); }} verejná trieda ChocolateProducer rozširuje SweetProducer {@Override public void produceSweet () {System.out.println ("Vyrába sa čokoláda"); }} public class CookieProducer rozširuje SweetProducer {@Override public void produceSweet () {System.out.println ("Cookie produced"); }} verejná trieda SweetCreator {súkromný zoznam sweetProducer; public SweetCreator (Zoznam sweetProducer) {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 (); }} 

V tomto príklade môžete vidieť, že SweetCreator trieda vie iba  SweetProducer trieda. Nepozná implementáciu každého z nich Sladké. Toto oddelenie nám dáva flexibilitu pri aktualizácii a opätovnom použití našich tried a údržba kódu je oveľa ľahšia. Pri navrhovaní kódu vždy hľadajte spôsoby, ako ho urobiť čo najpružnejším a udržiavateľnejším. polymorfizmus je veľmi účinná technika, ktorá sa používa na tieto účely.

Tip: @ Override anotácia zaväzuje programátora k použitiu rovnakého podpisu metódy, ktorý musí byť prepísaný. Ak metóda nie je prepísaná, dôjde k chybe kompilácie.

Covariantné typy návratov v prepísaní metódy

Je možné zmeniť návratový typ prepísanej metódy, ak ide o kovariantný typ. A kovariančný typ je v podstate podtrieda návratového typu. Zvážte príklad:

 verejná abstraktná trieda JavaMascot {abstrakt JavaMascot getMascot (); } verejná trieda Duke rozširuje JavaMascot {@Override Duke getMascot () {return new Duke (); }} 

Pretože Vojvoda je a JavaMascot, sme schopní zmeniť návratový typ pri prepísaní.

Polymorfizmus so základnými triedami Java

V základných triedach Java neustále používame polymorfizmus. Jeden veľmi jednoduchý príklad je, keď vytvoríme inštanciu ArrayList trieda vyhlasujúcaZoznam rozhranie ako typ:

 Zoznam zoznam = nový ArrayList (); 

Ak chcete ísť ďalej, zvážte túto ukážku kódu pomocou rozhrania Java Collections API bez polymorfizmus:

 verejná trieda ListActionWithoutPolymorphism {// Príklad bez polymorfizmu void executeVectorActions (vektorový vektor) {/ * opakovanie kódu tu * /} void executeArrayListActions (ArrayList arrayList) {/ * opakovanie kódu tu * /} void executeLinkedListActions (LinkedList linkedList) {/ * opakovanie kódu tu * /} void executeCopyOnWriteArrayListActions (CopyOnWriteArrayList copyOnWriteArrayList) {/ * opakovanie kódu tu * /}} verejná trieda ListActionInvokerWithoutPolymorphism {listAction.executeVectorActions (new Vector ()); listAction.executeArrayListActions (nový ArrayList ()); listAction.executeLinkedListActions (nový LinkedList ()); listAction.executeCopyOnWriteArrayListActions (nový CopyOnWriteArrayList ()); } 

Škaredý kód, nie? Predstavte si, že sa to snažíte udržať! Teraz sa pozri na rovnaký príklad s polymorfizmus:

 public static void main (Reťazec ... polymorfizmus) {ListAction listAction = nový ListAction (); listAction.executeListActions (); } public class ListAction {void executeListActions (List list) {// Execute actions with different lists}} public class ListActionInvoker {public static void main (String ... masterPolymorphism) {ListAction listAction = new ListAction (); listAction.executeListActions (nový vektor ()); listAction.executeListActions (nový ArrayList ()); listAction.executeListActions (nový LinkedList ()); listAction.executeListActions (nový CopyOnWriteArrayList ()); }} 

Výhodou polymorfizmu je flexibilita a rozšíriteľnosť. Namiesto vytvorenia niekoľkých rôznych metód môžeme deklarovať iba jednu metódu, ktorá prijíma všeobecné Zoznam typu.

Vyvolanie špecifických metód pri volaní polymorfnej metódy

Je možné vyvolať konkrétne metódy v polymorfnom volaní, ale robí to za cenu flexibility. Tu je príklad:

 verejná abstraktná trieda MetalGearCharacter {abstrakt void useWeapon (strunová zbraň); } verejná trieda BigBoss rozširuje MetalGearCharacter {@Override void useWeapon (strunná zbraň) {System.out.println ("Veľký šéf používa zbraň" +); } void giveOrderToTheArmy (String orderMessage) {System.out.println (orderMessage); }} verejná trieda SolidSnake rozširuje MetalGearCharacter {void useWeapon (strunná zbraň) {System.out.println ("Solid Snake používa zbraň" +); }} verejná trieda UseSpecificMethod {public static void executeActionWith (MetalGearCharacter metalGearCharacter) {metalGearCharacter.useWeapon ("SOCOM"); // Dolný riadok by nefungoval // metalGearCharacter.giveOrderToTheArmy ("Útok!"); if (metalGearCharacter instanceof BigBoss) {((BigBoss) metalGearCharacter) .giveOrderToTheArmy ("Útok!"); }} public static void main (String ... specificPolymorphismInvocation) {executeActionWith (new SolidSnake ()); executeActionWith (nový BigBoss ()); }} 

Technika, ktorú tu používame, je odlievanie, alebo zámernú zmenu typu objektu za behu.

Upozorňujeme, že je možné vyvolať konkrétnu metódu iba pri prenášaní generického typu na konkrétny typ. Dobrou analógiou by bolo výslovne povedať kompilátorovi: „Hej, viem, čo tu robím, takže objekt hodím na konkrétny typ a použijem konkrétnu metódu.“

Odkazujúc na vyššie uvedený príklad, je tu dôležitý dôvod, prečo kompilátor odmieta prijať vyvolanie konkrétnej metódy: trieda, ktorá sa odovzdáva, by mohla byť SolidSnake. V tomto prípade neexistuje žiadny spôsob, ako kompilátor zabezpečiť každú podtriedu MetalGearCharactergiveOrderToTheArmy deklarovaná metóda.

The inštancia vyhradené kľúčové slovo

Venujte pozornosť vyhradenému slovu inštancia. Pred vyvolaním konkrétnej metódy sme sa pýtali, či MetalGearCharacter je "inštanciaVeľký šéf. Ak si to nebolo a Veľký šéf napríklad by sme dostali nasledujúcu správu o výnimke:

 Výnimku vo vlákne „main“ java.lang.ClassCastException: com.javaworld.javachallengers.polymorphism.specificinvocation.SolidSnake nie je možné preniesť na com.javaworld.javachallengers.polymorphism.specificinvocation.BigBoss 

The Super vyhradené kľúčové slovo

Čo keby sme chceli odkázať na atribút alebo metódu z nadtriedy Java? V tomto prípade by sme mohli použiť Super vyhradené slovo. Napríklad:

 verejná trieda JavaMascot {void executeAction () {System.out.println ("Mascot Java sa chystá vykonať akciu!"); }} verejná trieda Duke rozširuje JavaMascot {@Override void executeAction () {super.executeAction (); System.out.println („Duke sa chystá udrieť!“); } public static void main (String ... superReservedWord) {new Duke (). executeAction (); }} 

Používanie vyhradeného slova Super v Vojvoda‘S executeAction metóda vyvolá metódu nadtriedy. Potom vykonáme konkrétnu akciu od Vojvoda. Preto môžeme obe správy vidieť na výstupe nižšie:

 Maskot Java sa chystá vykonať akciu! Vojvoda sa chystá udrieť! 

Prijmite výzvu polymorfizmu!

Poďme si vyskúšať, čo ste sa naučili o polymorfizme a dedičnosti. V tejto výzve ste dostali niekoľko metód od Matta Groeninga The Simpsons a vašou úlohou je odvodiť, aký bude výstup pre každú triedu. Ak chcete začať, pozorne analyzujte nasledujúci kód:

 verejná trieda PolymorphismChallenge {statická abstraktná trieda Simpson {void talk () {System.out.println ("Simpson!"); } prank chráneného prázdna (String prank) {System.out.println (prank); }} statická trieda Bart rozširuje Simpsona {String prank; Bart (Sláčikový žart) {this.prank = žart; } protected void talk () {System.out.println ("Zjedz moje šortky!"); } protected void prank () {super.prank (prank); System.out.println ("Knock Homer down"); }} statická trieda Lisa rozširuje Simpson {void talk (String toMe) {System.out.println ("I love Sax!"); }} public static void main (String ... doYourBest) {new Lisa (). talk ("Sax :)"); Simpson simpson = nový Bart ("D'oh"); simpson.talk (); Lisa lisa = nová Lisa (); lisa.talk (); ((Bart) simpson) .prank (); }} 

Co si myslis? Aký bude konečný výstup? Na to nepoužívajte IDE! Ide o to, aby ste si zdokonalili svoje schopnosti v oblasti analýzy kódu, takže si skúste určiť výstup sami.

Vyberte si svoju odpoveď a správnu odpoveď nájdete nižšie.

 A) Milujem Saxa! D'oh Simpson! D'oh B) Sax :) Zjedz mi trenírky! Milujem Sax! D'oh zrazil Homera dole C) Sax :) D'oh Simpson! Klepnite Homera dole D) Milujem Saxa! Zjedz moje kraťasy! Simpson! D'oh zrazil Homera 

Čo sa práve stalo? Pochopenie polymorfizmu

Pre nasledujúci spôsob vyvolania:

 nová Lisa (). talk ("Sax :)"); 

výstup bude „Milujem Sax!„Je to preto, že prechádzame okolo a String k metóde a Lisa má metódu.

Pre ďalšie vyvolanie:

 Simpson simpson = nový Bart ("D'oh");

simpson.talk ();

Výstup bude „Zjedz moje kraťasy!„Je to preto, lebo vytvárame inštancie Simpson typ s Bart.

Teraz skontrolujte tento, ktorý je trochu zložitejší:

 Lisa lisa = nová Lisa (); lisa.talk (); 

Tu používame metódu preťaženia dedičnosťou. Nepripravujeme nič k metóde hovoru, preto Simpson hovoriť metóda je vyvolaná. V takom prípade bude výstup:

 „Simpson!“ 

Tu je ešte jedna:

 ((Bart) simpson) .prank (); 

V takom prípade žart String bol schválený, keď sme vytvorili inštanciu Bart trieda s nový Bart („D'oh“);. V tomto prípade najskôr super.prank bude vyvolaná metóda, po ktorej bude nasledovať konkrétna žart metóda z Bart. Výstupom bude:

 „D'oh“ „zrazte Homera dole“ 

Video výzva! Ladenie polymorfizmu a dedičnosti Javy

Ladenie je jedným z najjednoduchších spôsobov, ako úplne absorbovať programovacie koncepty a zároveň vylepšiť váš kód. V tomto videu môžete sledovať, kým ladím a vysvetľujem výzvu polymorfizmu Java:

Bežné chyby s polymorfizmom

Častou chybou je, že je možné vyvolať konkrétnu metódu bez použitia castingu.

Ďalšou chybou je neistota, aká metóda sa vyvolá pri polymorfnej inštancii triedy. Pamätajte, že vyvolaná metóda je metódou vytvorenej inštancie.

Pamätajte tiež, že prepísanie metódy nie je preťaženie metódy.

Nie je možné prepísať metódu, ak sú parametre odlišné. To je možné zmeniť návratový typ prepísanej metódy, ak je návratový typ podtriedou metódy nadtriedy.

Čo si pamätať o polymorfizme

  • Vytvorená inštancia určí, ktorá metóda bude vyvolaná pri použití polymorfizmu.
  • The @ Override anotácia zaväzuje programátora k použitiu prepísanej metódy; ak nie, bude chyba kompilátora.
  • Polymorfizmus je možné použiť s normálnymi triedami, abstraktnými triedami a rozhraniami.
  • Väčšina návrhových vzorov závisí od určitej formy polymorfizmu.
  • Jediný spôsob, ako použiť konkrétnu metódu vo svojej polymorfnej podtriede, je použitie castingu.
  • Je možné navrhnúť výkonnú štruktúru vášho kódu pomocou polymorfizmu.
  • Spustite testy. Keď to urobíte, budete schopní zvládnuť tento silný koncept!

Odpovedať kľúč

Odpoveď na tohto vyzývateľa v jazyku Java je D. Výstup by bol:

 Milujem Sax! Zjedz moje kraťasy! Simpson! D'oh zrazil Homera 

Tento príbeh „Polymorfizmus a dedičstvo v Jave“ pôvodne publikoval server JavaWorld.

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