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 Juggy
Izvedena 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 "instanceof
” Veliki š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.