1 / 52

4IT101 devátá přednáška

4IT101 devátá přednáška. Dědičnost - pokračování. Specializace. Při práci s objekty dané třídy často odhalíme skupiny instancí se speciálními, avšak pro celou skupinu společnými vlastnostmi Příklady: Auta můžeme dělit na osobní, nákladní, autobusy a speciální

gary
Download Presentation

4IT101 devátá přednáška

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 4IT101 devátá přednáška Dědičnost - pokračování

  2. Specializace • Při práci s objekty dané třídy často odhalíme skupiny instancí se speciálními, avšak pro celou skupinu společnými vlastnostmi • Příklady: • Auta můžeme dělit na osobní, nákladní, autobusy a speciální • Vesmírná tělesa dělíme na hvězdy, planety a atd. • Osoby dělíme na muže a ženy • Mezi čtyřúhelníky můžeme vydělit obdélníky, mezi nimi pak čtverce • To, že je daný objekt členem speciální podskupinynijak neovlivňuje jeho členství v původní skupině

  3. Zobecnění • Často provádíme obrácený myšlenkový postup:u řady různých druhů objektů nacházíme společné vlastnostia definujeme pak společné skupiny • Příklady: • Lidé spolu s řadou zvířecích druhů tvoří skupiny savců • Auta, kola, povozy, vlaky, letadla, lodě & spol. jsou dopravní prostředky • Přirozené číslo je speciálním případem celého čísla,které je speciálním případem racionálního čísla,které je speciálním případem reálného čísla,které je speciálním případem komplexního čísla • V objektově orientovaných programech je vše považováno za objekt

  4. Co z předka lze používat (volat) v potomkovi? • Datové atributy • Metody • Konstruktory • Statické atributy • Statické metody Záleží na modifikátorech přístupu !!!!

  5. Co nabízí potomek ze svého předka? Záleží na modifikátorech, u překrytých metod pozdní vazba • Datové atributy • Metody • Konstruktory • Statické atributy • Statické metody Záleží na modifikátorech, včasná vazba

  6. Dědičnost a KONSTRUKTORY

  7. Dědičnost a konstruktory • Konstruktor se nedědí • Při spuštění konstruktoru se jako první automaticky volá konstruktor předka, pokud neurčíme který, volá se konstruktor bez parametru. • Pro určení volaného konstruktoru předka slouží klíčové slovo super

  8. this a super • this – odkaz na tuto instanci • this.data • this.metoda() • this() • super – odkaz na předka • super.data • super.metoda() • super()

  9. Volání konstruktoru předka, super public Ucet (int noveCislo, String jmeno, double castka){ cislo = noveCislo; vlastnik = jmeno; stav = castka; } public Ucet (int noveCislo, String jmeno){ cislo = noveCislo; vlastnik = jmeno; stav = 0; } • Máme několik problémů • třída Ucet nemá konstruktor bez parametru • i když vytváříme GiroUcet chceme určit číslo učtu, vlastníka a případně i stav účtu, navíc určujeme limit public ZiroUcet(intnoveCislo, String jmeno, double castka, double limit){ super(noveCislo, jmeno,castka); this.limit = limit; }

  10. public ZiroUcet (int cisloUctu, String vlastnik, double pocatecniVklad, double limit){ super(cisloUctu, vlastnik, pocatecniVklad); this.limit = limit; } public ZiroUcet (int cisloUctu, String vlastnik, double pocatecniVklad){ this(cisloUctu, vlastnik, pocatecniVklad, 0); } public ZiroUcet (int cisloUctu, String vlastnik){ this(cisloUctu, vlastnik, 0, 0); }

  11. Na co si dát u konstruktorů pozor • V konstruktoru bychom měli používatpouze soukromé a konečné metody • Tj. neměli by se volat metody, které lze překrýt, neboť nemusí být správně inicializovány datové atributy

  12. Hádanka class Predek { private String popis; Predek() { nastavPopis(); System.out.println(popis); } void nastavPopis() { popis="Předek"; } } class Potomek extends Predek { private String popis; Potomek () { nastavPopis(); } void nastavPopis() { popis="Potomek"; } } • Co se vypíše při vytvoření • instance potomka • new Potomek() • nic • řetězec Potomek • řetězec Předek • řetězec null

  13. String popis = null String popis = null clone() equals() finalize() hashCode() toString() ...... ..... Object Predek nastavPopis() nastavPopis() Potomek

  14. opakování kódu classPredek { privateString popis; Predek() { nastavPopis(); System.out.println(popis); } voidnastavPopis() { popis="Předek"; } } class Potomek extendsPredek { privateString popis; Potomek () { nastavPopis(); } voidnastavPopis() { popis="Potomek"; } }

  15. Object() {} String popis = null String popis = null “Potomek” Predek() { super(); nastavPopis(); System.out.println(popis); } clone() equals() finalize() hashCode() toString() ...... ..... Object (this.popis); Predek Potomek () { super(); nastavPopis(); } void nastavPopis() { this.popis="Potomek"; } nastavPopis() nastavPopis() Potomek

  16. Dědičnost a Modifikátory přístupu

  17. Modifikátory přístupu • private • „přátelský“ („packageprivate“) • protected • public • u datových atributů • u metod • u tříd – pozor na rozdíl u „normálních“ a vnitřních tříd

  18. protected a clone()

  19. Metoda clone() Predek p = newPredek(); Predek p2 = p; System.out.println(p + " "+ p2); System.out.println(p == p2); Předek Predek@9304b1 Predek@9304b1 true

  20. Metoda clone() Predek p = newPredek(); Predek p2 = (Predek)p.clone(); System.out.println(p + " "+ p2); System.out.println(p == p2);

  21. Metoda clone() public class Predek implements Cloneable{ privateString popis; Predek() { nastavPopis(); System.out.println(popis); } @Override public Object clone() throwsCloneNotSupportedException { returnsuper.clone(); }

  22. Metoda clone() Predek p = newPredek(); Predek p2 = null; try { p2 = (Predek)p.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } System.out.println(p + " "+ p2); System.out.println(p == p2); Předek Predek@9304b1 Predek@190d11 false

  23. PolymorfismusA Dědičnost

  24. Polymorfismus • při stejném volání metody se provádí různý kód. Který kód se provede závisí: • na parametrech metod, • na instanci (objektu), kterému je zpráva předávána, • přetěžování metod (overloading), též ad-hoc polymorphism • překrývání metod (overriding), též subtype polymorphism

  25. class Pes { public void stekej(){ System.out.print("haf"); } } class DomaciMazanek extends Pes { public void stekej(){ System.out.print("ňaf"); } } ..................... public static void main(String [] args){ Pes azor = new Pes(); Pes fifi = new DomaciMazanek(); azor.stekej(); fifi.stekej(); } a) haf haf b) haf ňaf c) ňaf haf Hádanka

  26. Polymorfismus v souvislosti s dědičností • Pro metody instancí platí tzv. pozdní vazba, viz volání metody stekej() v příkladu hádanky

  27. Metoda equals() a dědičnost • public boolean equals( Object o) • pravidla • je reflexivní, tj. x.equals(x) = true • je symetrická, tj. x.equals(y)= true pouze tehdy když y.equals(x)=true • je tranzitivní, tj. když x.equals(y)=true a y.equals(z) = true tak x.equals(z) musí vrátit také true • je konzistentní, tj. pro dvě instance vrací vždy stejnou hodnotu, • pro všechny hodnoty, které nejsou null, vrací x.equals(null) false opakování pravidel pro equals()

  28. Metoda equals() a dědičnost • třída Zvire – datový atribut druh, • potomek DomaciZvire – další datový atribut jmeno, ........... Zvire z1= new Zvire(“pes”); DomaciZvire z2 = new DomaciZvire(“pes”, “Rek”); ................ Mají si být tyto dvě instance rovny? Jak po přetypování z2 na typ Zvire?

  29. Metoda equals() a dědičnost • předek se má rovnat potomkovi • použijeme instanceof v metodě equals(), • předek se nemá rovnat potomkovi • porovnáváme přes shodnost třídy, označení třídy získáme metodou getClass() ze třídy Object

  30. class DomaciZvire extends Zvire { private String jmeno; public boolean equals( Object o){ if (!(o instanceof DomaciZvire)) return false; DomaciZvire z = (DomaciZvire) o; String dr = z.getDruh(); String jm = z.jmeno; return (dr.equals(getDruh()) && jmeno.equals(jm)); } ....................... implementace equals() s instanceOf class Zvire { private String druh; public boolean equals( Object o){ if (!(o instanceof Zvire)) return false; Zvire z = (Zvire) o; String dr = z.druh; return druh.equals(dr); } ......

  31. ........... Zvire z1= new Zvire(“pes”); DomaciZvire z2 = new DomaciZvire(“pes”, “Rek”); z1.equals(z2); z2.equals(z1); ................ Výsledkem tohoto porovnání je true (pes je pes) Výsledkem tohoto porovnání je false (porovnávám domácí zvíře a zvíře) řešení – v potomcích by se nemělo překrývat equals()

  32. equals() – předek se nerovná potomkovi class Zvire { private String druh; public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; String dr = z.druh; return druh.equals(dr); }

  33. DědičnostA statické prvky

  34. Statické prvky a dědičnost • statické prvky se volají jménem třídy => jména tříd se nedědí, nepřekrývají, • statické prvky používají včasnou vazbu a ne pozdní vazbu,

  35. class Pes { public static void stekej(){ System.out.print("haf"); } } class DomaciMazanek extends Pes { public static void stekej(){ System.out.print("ňaf"); } } ..................... public static void main(String [] args){ Pes azor = new Pes(); Pes fifi = new DomaciMazanek(); azor.stekej(); fifi.stekej(); } a) haf ňaf b) haf haf c) ňaf haf Hádanka

  36. Abstraktní třídy

  37. Abstraktní třídy • abstraktní třídy – v situaci, kdy nemá smysl vytvářet instanci této třídy • klíčové slovo abstract, • abstraktní metody (nemusí být), • může mít konkrétní datové atributy, konkrétní metody, • třídy Motýl a Včela • abstraktní třída LetajícíHmyz

  38. public abstract class LetajiciHmyz { private Pozice pozice; public abstract void jedenPohyb (); protected void preletni() { // vyber náhodně květinu v nejbližším okolí // přesuň se na vybranou květinu } protected boolean naKvetineSNektarem() { if (pozice.jeKvetina()) { Kvetina kvetina = pozice.getKvetina(); return kvetina.maNektar(); } else { return false; } } }

  39. Používání dědičnosti – pravidla a omezení

  40. Důvody pro použití dědičnosti • Specializace • Překrývání metod a polymorfismus • Znovupoužití kódu

  41. Pravidla pro použití dědičnosti • podtřída by měla být podtypem své nadtřídy. Pokud máte pocit, že by třída B měla být potomkem třídy A, položte si otázku: "Je každé B skutečně nějakým A?" Pokud si odpovíte záporně, tak třída B by neměla být potomkem třídy A, ale měla by obsahovat instanci třídy A jako datový atribut – třída A je poté detailem implementace B

  42. Pravidla pro použití dědičnosti • pokud jsou třídy B a C potomkem třídy A, neměla by nastat situace, kdy existují objekty, které by měly být současně B a C

  43. Pravidla pro použití dědičnosti • pokud se nějaká instance stane odrazem nějakého reálného objektu, neměla by v rámci aplikace vzniknout potřeba změnit instanci na jiný typ bez podstatné změny reálného objektu. Existence instance by měla sledovat existenci odpovídajícího objektu s přihlédnutím doby používání aplikace a s přihlédnutím k administrativnímu rozsahu použití aplikace

  44. Porušení vztahu „je nějakým“ při návrhu dědičnosti

  45. Dědičnost narušuje zapouzdření • máme třídu Kosodelnik, chceme vytvořit třídu Obdelnik

  46. Dědičnost narušuje zapouzdření • varianta a: obdélník je potomkem kosodélníka • problém zavoláním zděděných metod nastavUhel (uhel) činastavRozmery(stranaA, stranaB, uhel)vznikne z obdélníka kosodélník, public class Obdelnik extends Kosodelnik { public Obdelnik(double stranaA, double stranaB) { super(stranaA, stranaB, 90); } }

  47. public class Obdelnik extends Kosodelnik { // ... konstruktor vynechán @Override public void nastavUhel(double uhel) { if (uhel != 90) { throw new UnsupportedOperationException( "U obdelníka musí být úhel 90°"); } } @Override public void nastavRozmer(double stranaA, double stranaB, double uhel) { if (uhel != 90) { throw new UnsupportedOperationException( "U obdelníka musí být úhel 90°"); } nastavRozmer(stranaA, stranaB); } } • Co se stane při zavolání metody nastavRozmer u obdelníka (následující kód): • Obdelnik obd = new Obdelnik(3,5); • obd.nastavRozmer(5,10); • nastaví se nový rozměr, obdélník bude dále obdélníkem • nastaví se nový rozměr, z obdélníku se stane kosodélník • kód skončí výjimkou UnsupportedOperationException • kód skončí výjimkou NullPointerException • kód skončí výjimkou StackOverflowError • kód skončí nekonečným cyklem Dědičnost narušuje zapouzdření public class Kosodelnik { // .... část vynechána public void nastavRozmer(double stranaA, double stranaB, double uhel) { this.stranaA = stranaA; this.stranaB = stranaB; this.uhel = uhel; } public void nastavRozmer(double stranaA, double stranaB) { nastavRozmer(stranaA, stranaB, this.uhel); } public void nastavUhel(double uhel) { this.uhel=uhel; } } • první řešení - překrytí problematických metod nastavUhel a nastavRozmer • nejdříve si ukážeme tyto metody ve třídě Kosodelník, • potom jejich překrytí ve třídě Obdelnik

More Related