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

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

Upload: gary

Post on 24-Feb-2016

48 views

Category:

Documents


0 download

DESCRIPTION

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í - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 4IT101  devátá  přednáška

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

Dědičnost - pokračování

Page 2: 4IT101  devátá  přednáška

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ě

Page 3: 4IT101  devátá  přednáška

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

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

Co z předka lze používat (volat) v

potomkovi?• Datové atributy• Metody• Konstruktory• Statické atributy• Statické metody

Záleží na modifikátorec

h přístupu !!!!

Page 5: 4IT101  devátá  přednáška

Co nabízí potomek ze svého předka?

• Datové atributy• Metody• Konstruktory• Statické atributy• Statické metody

Záleží na modifikátorech, u překrytých metod

pozdní vazba

Záleží na modifikátorech, včasná vazba

Page 6: 4IT101  devátá  přednáška

DĚDIČNOST A KONSTRUKTORY

Page 7: 4IT101  devátá  přednáška

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

Page 8: 4IT101  devátá  přednáška

this a super• this – odkaz na tuto instanci

– this.data– this.metoda()– this()

• super – odkaz na předka– super.data– super.metoda()– super()

Page 9: 4IT101  devátá  přednáška

Volání konstruktoru předka, super

• 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 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;} public ZiroUcet (int noveCislo, String jmeno, double castka,

double limit) { super(noveCislo, jmeno,castka);this.limit = limit;

}

Page 10: 4IT101  devátá  přednáška

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); }

Page 11: 4IT101  devátá  přednáška

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

Page 12: 4IT101  devátá  přednáška

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()

a) nicb) řetězec Potomekc) řetězec Předekd) řetězec null

Page 13: 4IT101  devátá  přednáška

String popis = null String popis = null

clone()equals()finalize()

hashCode()toString()

...........

nastavPopis()

Object

Predek

PotomeknastavPopis()

Page 14: 4IT101  devátá  přednáška

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";}

}

Page 15: 4IT101  devátá  přednáška

String popis = null String popis = null

clone()equals()finalize()

hashCode()toString()

...........

nastavPopis()

Object

Predek

PotomeknastavPopis()

Predek() { super(); nastavPopis(); System.out.println(popis);}

Potomek () { super(); nastavPopis();}

Object(){}

void nastavPopis() {this.popis="Potomek";}

“Potomek”

(this.popis);

Page 16: 4IT101  devátá  přednáška

DĚDIČNOST A MODIFIKÁTORY PŘÍSTUPU

Page 17: 4IT101  devátá  přednáška

Modifikátory přístupu • private• „přátelský“ („package

private“)• 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

Page 18: 4IT101  devátá  přednáška

protected a clone()

Page 19: 4IT101  devátá  přednáška

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

PředekPredek@9304b1 Predek@9304b1true

Page 20: 4IT101  devátá  přednáška

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

Page 21: 4IT101  devátá  přednáška

Metoda clone()public class Predek implements Cloneable{

private String popis;

Predek() {nastavPopis();System.out.println(popis);

}

@Overridepublic Object clone() throwsCloneNotSupportedException {

return super.clone();}

Page 22: 4IT101  devátá  přednáška

Metoda clone()Predek p = new Predek();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@190d11false

Page 23: 4IT101  devátá  přednáška

POLYMORFISMUSA DĚDIČNOST

Page 24: 4IT101  devátá  přednáška

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

Page 25: 4IT101  devátá  přednáška

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 hafb) haf ňafc) ňaf haf

Page 26: 4IT101  devátá  přednáška

Polymorfismus v souvislosti s dědičností

• Pro metody instancí platí tzv. pozdní vazba, viz volání metody stekej() v příkladu hádanky

Page 27: 4IT101  devátá  přednáška

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()

Page 28: 4IT101  devátá  přednáška

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?

Page 29: 4IT101  devátá  přednáška

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

Page 30: 4IT101  devátá  přednáška

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));

}.......................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);

}......

impl

emen

tace

equ

als(

) s

inst

ance

Of

Page 31: 4IT101  devátá  přednáška

...........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()

Page 32: 4IT101  devátá  přednáška

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);

}

Page 33: 4IT101  devátá  přednáška

DĚDIČNOSTA STATICKÉ PRVKY

Page 34: 4IT101  devátá  přednáška

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,

Page 35: 4IT101  devátá  přednáška

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 ňafb) haf hafc) ňaf haf

Page 36: 4IT101  devátá  přednáška

ABSTRAKTNÍ TŘÍDY

Page 37: 4IT101  devátá  přednáška

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

Page 38: 4IT101  devátá  přednáška
Page 39: 4IT101  devátá  přednáška

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;}

}}

Page 40: 4IT101  devátá  přednáška
Page 41: 4IT101  devátá  přednáška
Page 42: 4IT101  devátá  přednáška

POUŽÍVÁNÍ DĚDIČNOSTI – PRAVIDLA A OMEZENÍ

Page 43: 4IT101  devátá  přednáška

Důvody pro použití dědičnosti

• Specializace• Překrývání metod a polymorfismus• Znovupoužití kódu

Page 44: 4IT101  devátá  přednáška

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

Page 45: 4IT101  devátá  přednáška

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

Page 46: 4IT101  devátá  přednáška

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

Page 47: 4IT101  devátá  přednáška

Porušení vztahu „je nějakým“ při návrhu

dědičnosti

Page 48: 4IT101  devátá  přednáška

Dědičnost narušuje zapouzdření

• máme třídu Kosodelnik, chceme vytvořit třídu Obdelnik

Page 49: 4IT101  devátá  přednáška

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); }}

Page 50: 4IT101  devátá  přednáška

Dědičnost narušuje zapouzdření

• 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

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; }}

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);

a) nastaví se nový rozměr, obdélník bude dále obdélníkemb) nastaví se nový rozměr, z obdélníku se stane kosodélníkc) kód skončí výjimkou UnsupportedOperationExceptiond) kód skončí výjimkou NullPointerExceptione) kód skončí výjimkou StackOverflowErrorf) kód skončí nekonečným cyklem

Page 51: 4IT101  devátá  přednáška

Dědičnost narušuje zapouzdření

• správné řešení: public void nastavRozmer(double stranaA,

double stranaB, double uhel) {

if (uhel != 90) { throw new UnsupportedOperationException(

"U obdelníka musí být úhel 90°"); } super.nastavRozmer(stranaA, stranaB, 90); }

Page 52: 4IT101  devátá  přednáška

Použití skládání místo dědičnosti

public class Obdelnik { private Kosodelnik kosodelnik; public Obdelnik(double stranaA, double stranaB) { kosodelnik = new Kosodelnik(stranaA, stranaB, 90); } public double obvod() { return kosodelnik.obvod(); } public double obsah() { return kosodelnik.obsah(); } public void nastavRozmer(double stranaA, double stranaB) {

kosodelnik.nastavRozmer(stranaA, stranaB); } public double getStranaA() {

return kosodelnik.getStranaA(); } public double getStranaB() { return kosodelnik.getStranaB(); }}