Obsah přednášky. dědičnost modifikátory (specifikátory) přístupu

Rozměr: px
Začít zobrazení ze stránky:

Download "Obsah přednášky. dědičnost modifikátory (specifikátory) přístupu"

Transkript

1 OOPR_08 1

2 Obsah přednášky dědičnost modifikátory (specifikátory) přístupu private, public, protected konstruktor v dědičnosti deklarace nových objektů rozšiřování & přepisování (zastiňování) metod pravidla pro přetypování proměnných třída Object a její metody přetěžované metody 2

3 Dědičnost dědičnost je další základní charakteristika objektově orientovaného programování dědění tříd patří k nejvíce využívaným, ale také k nejvíce zneužívaným rysům objektově orientovaného programování jak využívat a jak nepoužívat dědičnost 3

4 Specializace - Zobecnění dva navzájem protichůdné pojmy využívané při tvorbě hierarchických struktur specializace: osoby na OU zaměstnanci administrativa učitelé studenti denní interní externí bakalářský program magisterský program 4

5 Specializace - Zobecnění zobecnění obrácený postup, zkušenosti získané ze zvláštních objektů zobecňujeme na rozsáhlejší obecnou skupinu např. čtverec, trojúhelník, kruh rozdílné tvary, zobecnění ní speciální případy obecného geometrického tvaru osoby mající něco společného s OU 5

6 Dědičnost tříd hierarchie s UML Student Bakalář Magistr Doktorand Denní_bakalář Distanční_bakalář Denní_magistr Distanční_magistr 6

7 Dědičnost versus kompozice při tvorbě software rozlišujeme mezi relací is-a a relací has-a relace has-a reprezentuje skládání objektů: kompozice, agregace relace is-a reprezentuje dědičnost např. auto je dopravní prostředek, na rozdíl od auto má volant, auto má motor atd. výhodou dědičnosti je, že nové třídy mohou dědit z vytvořených knihoven tříd, což značně urychluje tvorbu programových systémů (znovupoužitelnost na úrovni kódu) 7

8 Prostředky pro realizaci dědičnosti v OOP Jedním z nástrojů umožňující realizaci popsaných vlastností je dědičnost tříd. Má-li nějaká množina instancí specifické vlastnosti, které je možno využít, a nebo respektovat, můžeme pro ni definovat zvláštní podtřídu, která zdědí všechny původní vlastnosti třídy a přidá ty, které popisují její speciální vlastnosti. Při zobecňování máme-li několik tříd, jejíchž instance vykazují nápadně podobné vlastnosti, můžeme jim definovat společnou nadtřídu, která bude na jednom místě definovat jejich společné vlastnosti. 8

9 Dědičnost v Javě Dědičnost v Javě má dvě formy: dědičnost tříd (class inheritance) dědičnost rozhraní (interface inheritance) dědičnost tříd podporuje základní formu znovupoužitelnosti kódu, což znamená, že podtřída zdědí metody nadtřídy a její datové atributy dědičnost také umožňuje využívat konstrukce polymorfismu (vícetvarosti) v polymorfismu mají různé metody uvnitř hierarchie tříd stejné názvy, ale odlišnou funkcionalitu. 9

10 Osoba Student jednoduchý příklad Osoba datové atributy: jméno pohlaví datumnarozeni metody konstruktory getvek dynamicky se měnící datový atribut tostring tisk Implicitně je každá deklarovaná třída podtřídou třídy Object 10

11 Student datové atributy obor studia metody konstruktory tostring Osoba Student jednoduchý příklad 11

12 import java.util.calendar; public class Osoba { private String jmeno; private String pohlavi; private int roknarozeni; Poznámky public Osoba() { jmeno="neuvedeno"; pohlavi="neuvedeno"; roknarozeni = 0; public Osoba(String jmeno, String pohlavi, int r) { this.jmeno = jmeno; this.pohlavi= pohlavi; roknarozeni = r; public int getvek(){ Calendar c = Calendar.getInstance(); int aktrok = c.get(1); return aktrok - roknarozeni; public String tostring() { return String.format(" %s: %s %s: %s %s: %d\n", "jmeno",jmeno,"pohlavi",pohlavi,"vek",this.getvek()); public void tisk() { System.out.println(this.getClass().getName()+this.toString()); public String getjmeno() { return jmeno; public String getpohlavi() { return pohlavi; 12

13 public class Student extends Osoba { private String obor; Poznámky public Student() { super(); obor="neuveden"; public Student(String jmeno, String pohlavi, int roknar, String obor) { super(jmeno, pohlavi, roknar); this.obor= obor; public String tostring() { return String.format("%s %s: %s\n",super.tostring(), "obor",obor); public String getobor() { return obor; 13

14 public class OsobaTest { Poznámky public static void main(string[] args) { Osoba o1 = new Osoba("Jana", "zena", 1980); Osoba o2 = new Osoba("David", "muz", 1984); Osoba o3; Student s3; Student s1 = new Student("Iveta","zena", 1979, "informatika"); Student s2 = new Student("Josef","muz",1986,"matematika"); o1.tisk(); o2.tisk(); s1.tisk(); s2.tisk(); o3 = s1; //System.out.println("Jmeno: "+o3.jmeno+" pohlavi: "+ // o3.pohlavi+ " vek: "+o3.getvek()); // k pristupu k datovym atributum je nutno pouzit // pristupove metody System.out.println("Jmeno: "+o3.getjmeno()+" pohlavi: "+ o3.getpohlavi()+ " vek: "+o3.getvek()); //System.out.println("Obor: "+o3.getobor()); // nelze pouzit System.out.println("o3.tisk()"); o3.tisk(); //funguje s3 = (Student) o3; //nutno provest pretypovani - upcasting System.out.println("s3.tisk()"); s3.tisk(); 14

15 simple.osoba jmeno: Jana pohlavi: zena vek: 26 Poznámky simple.osoba jmeno: David pohlavi: muz vek: 22 simple.student jmeno: Iveta pohlavi: zena vek: 27 obor: informatika simple.student jmeno: Josef pohlavi: muz vek: 20 obor: matematika Jmeno: Iveta pohlavi: zena vek: 27 o3.tisk() simple.student jmeno: Iveta pohlavi: zena vek: 27 obor: informatika s3.tisk() simple.student jmeno: Iveta pohlavi: zena vek: 27 obor: informatika 15

16 Modifikátory přístupu private datové atributy, z vně třídy nepřístupné konstruktory, z vně třídy nepřístupné metody modifikátor private umožňuje přístup k datovým atributům a metodám pouze uvnitř dané třídy. Ty nejsou děděny do podtříd. 16

17 Modifikátory přístupu public veřejně přístupné metody, konstruktory, datové atributy v návrhovém vzoru přepravka modifikátor public umožňuje přístup k datovým atributům a metodám z objektů dané třídy a objektů jejich podtříd. 17

18 Přístup protected modifikátor protected mezistupeň ochrany mezi public a private modifikátor protected je přístupný členům nadtřídy (datové atributy a metody) členům podtřídy členům jiných tříd ve stejném balíčku přístup podtřídy ke členům nadtřídy klíčové slovo super a tečka (.) 18

19 Modifikátory přístupu modifikátor public a protected se nemění v podtřídách, v podtřídách je umožněn přístup pomocí jmen když podtřída redefinuje metodu nadtřídy, metoda nadtřídy může být zpřístupněna na z podtřídy pomocí klíčového slova super ( super.tostring(); ) metody podtřídy nemají přímý přístup k private členům nadtřídy, musí k tomu použít jiné než private metody nadtřídy, zděděné podtřídou 19

20 Modifikátory přístupu v podtřídě nemůžeme k datovým atributům deklarovaným jako private přistupovat přímo využít modifikátor protected (problém umožní také přímý přístup všem třídám v balíčku) využít veřejné ejné (public) přístupové metody 20

21 Modifikátor protected Použití modifikátoruprotected pro datové atributy (instanční proměnné) Výhody podtřídy mohou modifikovat přímo datové atributy (tečková notace) Výkonnost aplikace se trochu zvýší Nevýhody Sníží se režie přístupových a modifikačních funkcí Žádná kontrola vstupních dat podtřída může přiřadit nepovolenou hodnotu atributy nadtřídy Implementační závislost metody podtřídy jsou pravděpodobněnji více závislé na implementaci nadtřídy změny implementace nadtřídy mohou vyústit ve změnu podtřídy Vede to ke křehkému software 21

22 Rezervace jízdenek Datum den: int mesic: int rok: int Rezervace tostring() tisk() Osoba jmeno: String pohlavi: String RezervaceLetenek let: String sedadlo: String RezervaceJizdenek vlak: String vagon: int sedadlo: int 22

23 import java.util.calendar; public class Datum { private int den; // 1-31 private int mesic; // 1-12 private int rok; private Calendar kalendar = Calendar.getInstance(); Poznámky // kalendar.get(1) = rok, kalendar.get(2) +1 = mesic, kalendar.get(5) = den //konstruktory public Datum( int den,int mesic, int rok) { this.mesic = mesickontrola( mesic ); this.rok = kontrolarok(rok); this.den = denkontrola( den); public Datum() { mesic = kalendar.get(2) + 1; den = kalendar.get(5); rok = kalendar.get(1); public Datum(int den) { mesic = kalendar.get(2) + 1; this.den = denkontrola(den); rok = kalendar.get(1);

24 public Datum(int den, int mesic) { this.mesic = mesickontrola(mesic); this.den = denkontrola(den); rok = kalendar.get(1); Poznámky public Datum(int den, String mesic, int rok) { this.mesic = mesickontrola(mesic); this.den = denkontrola(den); this.rok = kontrolarok(rok); public Datum(int den, Mesic mesic, int rok) { this.mesic = mesic.ordinal() + 1; //System.out.println("mesic: " + this.mesic); this.den = denkontrola(den); this.rok = rok; // kopirovaci konstruktor public Datum(Datum d) { mesic = d.getmesic(); den = d.getden(); rok = d.getrok();

25 // pristupove a modifikacni metody... private int mesickontrola( int mesic) { if ( mesic > 0 && mesic <= 12 ) return mesic; else { System.out.printf( "Neplatny mesic (%d) nastaveni na 1.", mesic ); return 1; Poznámky private int mesickontrola(string mesic) { String[] mesice = {"leden", "unor", "brezen", "duben", "kveten", "cerven", {"leden", "unor", "brezen", "duben", "kveten", "cerven", "cervenec", "srpen", "zari", "rijen", "listopad", "prosinec"; for(int i = 0; i < mesice.length; i++) if(mesic == mesice[i]) return i+1; System.out.printf("neplatny mesic (%s) + nastaveni na leden ", mesic); return 1;

26 private int denkontrola( int den ) { int dnuvmesici[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ; Poznámky // kontrola rozsahu dne v mesici if ( den > 0 && den <= dnuvmesici[ getmesic() ] ) return den; // kontrola prestupny rok if ( getmesic() == 2 && getden() == 29 && ( getrok() % 400 == 0 ( getrok() % 4 == 0 && getrok() % 100!= 0 ) ) ) return den; System.out.printf( "Neplatny den (%d) nastaveni na 1.", den ); return 1;

27 public int kontrolarok(int r) { if(r>=1900 && r <= 2100) return r; else return kalendar.get(1); public String tostring() { return String.format( "%d/%d/%d", getden(), getmesic(), getrok()); public void tisk(){ System.out.println(toString()); Poznámky public enum Mesic { LEDEN, UNOR, BREZEN, DUBEN, KVETEN, CERVEN, CERVENEC, LEDEN, UNOR, BREZEN, DUBEN, KVETEN, CERVEN, CERVENEC, SRPEN, ZARI, RIJEN, LISTOPAD, PROSINEC

28 public class Rezervace { Datum datum; Osoba zakaznik; Poznámky public Rezervace(Datum datum){ this.datum = datum; public void setzakaznik(osoba o){ zakaznik = osoba; public Osoba getzakaznik(){ return zakaznik; public String tostring(){ return String.format("Zakaznik: %sdatum: %s", zakaznik.tostring(), datum.tostring()); public void tisk(){ System.out.print(this.toString());

29 public class RezervaceLetenek extends Rezervace { private String let; private String sedadlo; Poznámky public RezervaceLetenek(Datum d, String l, String s){ super(d); let = l; sedadlo = s; public String getlet(){ return let; public String getsedadlo() { return sedadlo; public String tostring() { return String.format("%s \nlet: %s sedadlo: %s\n", super.tostring(),getlet(),getsedadlo());

30 public class RezervaceJizdenek extends Rezervace { private String vlak; private int vagon; private int sedadlo; Poznámky public RezervaceJizdenek(Datum d, String v, int vg, int s){ super(d); vlak = v; vagon = vg; sedadlo = s; public String getvlak(){ return vlak; public int getvagon(){ return vagon; public int getsedadlo(){ return sedadlo; public String tostring(){ return String.format("%s\nVlak: %s vagon: %4d, + sedadlo: %3d\n", super.tostring(),vlak, vagon, sedadlo);

31 public class RezervaceTest { public static void main(string[] args) { 1 RezervaceJizdenek jizdenka = new RezervaceJizdenek(new Datum(25), 2 "Pendolino",506,28); 3 4 Osoba osoba = new Osoba("Adam","muz"); 5 jizdenka.setzakaznik(osoba); 6 7 RezervaceLetenek letenka = new RezervaceLetenek( 8 new Datum(16, Mesic.UNOR, 2014), "Ok 225","14A"); 9 osoba = new Osoba("Alena","zena"); 10 letenka.setzakaznik(osoba); 11 // tisk rezervace jizdenky 11 // tisk rezervace jizdenky 12 jizdenka.tisk(); 13 // tisk rezervace letenky 14 letenka.tisk(); System.out.println("Let: "+letenka.getlet()); //chybny pristup - informace z nadtridy pouze 19 // prostrednictvim pristupovych metod 20 System.out.println("Jmeno zakaznika: " + letenka.zakaznik.jmeno); 21 // spravne 22 System.out.println("Jmeno klienta: " + 23 letenka.getzakaznik().getjmeno()+"\n"); Poznámky

32 24 // kvalifikace promenne rezervace 25 Rezervace rezervace; 26 rezervace = jizdenka; // pretypovani na predka 27 rezervace.tisk(); 28 rezervace = letenka; // pretypovani na predka 29 rezervace.tisk(); 30 System.out.println("Jmeno: " + rezervace.getzakaznik().getjmeno()+ 31 " pohlavi: "+rezervace.getzakaznik().getpohlavi()); 32 //metoha getlet() není definovana pro tridu Reservace; 33 //System.out.println("Let: "+rezervace.getlet()); RezervaceLetenek letenkax; 36 letenkax = (RezervaceLetenek) rezervace; 37 System.out.println("Let: "+letenkax.getlet()); 37 System.out.println("Let: "+letenkax.getlet()); Poznámky

33 Zakaznik: jmeno: Adam pohlavi: muz Datum: 25/7/2013 Vlak: Pendolino vagon: 506, sedadlo: 28 Poznámky Zakaznik: jmeno: Alena pohlavi: zena Datum: 16/2/2014 Let: Ok 225 sedadlo: 14A Let: Ok 225 Jmeno klienta: Alena Zakaznik: jmeno: Adam pohlavi: muz Datum: 25/7/2013 Vlak: Pendolino vagon: 506, sedadlo: 28 Zakaznik: jmeno: Alena pohlavi: zena Datum: 16/2/2014 Let: Ok 225 sedadlo: 14A Jmeno: Alena pohlavi: zena Let: Ok 225

34 Třídy a podtřídy Hierarchie dědičnosti Vztahy dědičnosti: stromová hierarchická struktura Každá třída se stává nadtřídou nebo dodává data/ chování (metody) jiným třídám podtřídou dědí data/ chování (metody) z jiných tříd (bezprostředně z jedné) 34

35 Třídy podtřídy Jedním z problémů dědičnosti je, že podtřída může zdědit metody, které nepotřebuje, nebo nemusí mít. Podtřída často potřebuje upravit zděděnou metodu. V těchto případech podtřída redefinuje (override, zastiňuje) metodu nadtřídy se svoji vhodnou implementací. 35

36 Třída Object a další třídy každá třída v Javě, kromě třídy java.lang.object má nadtřídu. Třída Object nemá žádnou nadtřídu a tvoří kořen hierarchie tříd. Třída Object poskytuje svým podtřídám pouze metody ve skutečnosti každá javovská třída dědí metody třídy Object přímo (explicitně uvede klíčové slovo extends) nebo nepřímo (neuvede klíčové slovo extends a dědí také) 36

37 Třída Object a další třídy pokud nová třída neuvede, že je podtřídou jiné třídy, je implicitně podtřídou třídy Object 37

38 Třída Object Metoda clone Popis metoda protected, bez argumentů, vytváří kopii objektu na který je zavolána; v dané třídě se předpokládá redefinování této metody jako public, která by měla implementovat rozhraní Clonable (balíček java.lang). Implicitní implementace této metody provádí tzv. shallow copy equals finalize getclass metoda porovnává dva objekty a vrací true v případě rovnosti a false při nerovnosti; object1.equals(object2); metoda předpokládá redefinici ve třídách použití metoda protected, je volána garbage collectorem ke konečnému uklízení, nemá parametry, vrací void, zřídka kdy používaná metoda vrací informace o dané třídě, jméno třídy dostaneme pomocí metody getname() 38

39 Třída Object Metoda Popis hashcode hashovací tabulka je datová struktura, která přiřazuje objekt klíč k objektu hodnota, hashcode je hodnota vrácená metodou hashcode, která se používá ke stanovení místa, kde bude uložena odpovídající hodnota notify notifyall wait tostring metody využívané pro multithreading (aktivní objekty) tato metoda vrací řetězcovou reprezentaci objektu 39

40 // CommissionEmployee class represents a commission employee. public class CommissionEmployee extends Object { private String firstname; private String lastname; private String socialsecuritynumber; private double grosssales; // gross weekly sales private double commissionrate; // commission percentage // five-argument constructor public CommissionEmployee( String first, String last, String ssn, double sales, double rate ) { // implicit call to Object constructor occurs here firstname = first; lastname = last; socialsecuritynumber = ssn; setgrosssales( sales ); // validate and store gross sales setcommissionrate( rate ); // validate and store commission rate // end five-argument CommissionEmployee constructor Poznámky Konstruktor se nedědí, ale třída CommissionEmployee volá konstruktor třídy Object implicitně Prvním úkolem konstruktoru podtřídy je volat přímý konstruktor nadtřídy, explicitně nebo implicitně, aby se zdědily datové atributy nadtříd a byly správně inicializované // set first name public void setfirstname( String first ) { firstname = first; // end method setfirstname 40

41 Konstruktor v podtřídách vytvoření objektu podtřídy řetězec volání konstruktorů konstruktor podtřídy volá konstruktor nadtřídy implicitně nebo explicitně pravidla hierarchie dědičnosti posledním volaným konstruktorem v řetězci je konstruktor třídy Object tělo konstruktoru původního objektu (kde vše začalo) podtřídy ukončuje provádění jako poslední 41

42 Příklad hierarchie tříd 42

43 public class Zaznam { Poznámky private int klic; public Zaznam() { klic = 0; public Zaznam(int klic) { this.klic = klic; public String tostring() { return String.format("%5d\n",klic); //vyuziva se ve vsech nadtridach public void tisk() { System.out.println(this.getClass().getName()+this.toString()); public int getklic() { return klic; 43

44 public class Kniha extends Zaznam { Poznámky private String autor; private String nazev; public Kniha() { super(); autor = "neuveden"; nazev= "neuveden"; public Kniha(int klic, String autor, String nazev) { super(klic); this.autor = autor; this.nazev= nazev; public String tostring() { return String.format("%s %s: %s %s: %s\n",super.tostring(), "autor",autor,"nazev",nazev); public String getautor() { return autor; public String getnazev() { return nazev; 44

45 public class Osoba extends Zaznam { private String jmeno; private String pohlavi; Poznámky public Osoba() { super(); jmeno="neuvedeno"; pohlavi="neuvedeno"; public Osoba(int klic, String jmeno, String pohlavi) { super(klic); this.jmeno = jmeno; this.pohlavi= pohlavi; public String tostring() { return String.format("%s %s: %s %s: %s\n",super.tostring(), "jmeno",jmeno,"pohlavi",pohlavi); public String getjmeno() { return jmeno; public String getpohlavi() { return pohlavi; 45

46 public class Student extends Osoba { private String obor; Poznámky public Student() { super(); obor="neuveden"; public Student(int klic, String jmeno, String pohlavi, String obor) { super(klic, jmeno, pohlavi); this.obor= obor; public String tostring() { return String.format("%s %s: %s\n",super.tostring(), "obor",obor); public String getobor() { return obor; 46

47 public class Pracovnik extends Osoba { private String pozice; private int plat; Poznámky public Pracovnik() { super(); pozice= "neuvedena"; plat = 0; public Pracovnik(int klic, String jmeno, String pohlavi, String pozice, int plat) { super(klic, jmeno, pohlavi); this.pozice= pozice; this.plat= plat; public String tostring() { return String.format("%s %s: %s %s: %6d\n", super.tostring(),"pozice",pozice,"plat",plat); public String getpozice() { return pozice; public int getplat() { return plat; 47

48 public class ZaznamTest { public static void main(string args[]) { Zaznam z, z1; Osoba o; Pracujici p1; Kniha k = new Kniha(15,"Nemcova","Babicka"); Pracujici p = new Pracujici(44,"Jana","zena","ucetni",20000); k.tisk(); p.tisk(); z = p; System.out.println("Zaznam tisk & pracujici\n"); z.tisk(); //System.out.println("plat: "+z.getplat()); System.out.println("Zaznam tisk & pracujici P1\n"); p1= (Pracujici)z; p1.tisk(); System.out.println("Zaznam tisk & pracujici OSOBA\n"); o = (Osoba)z; //pretypuje se jako Pracujici o.tisk(); Poznámky 48

49 Poznámky zaznam.kniha 15 autor: Nemcova nazev: Babicka zaznam.pracujici 44 jmeno: Jana pohlavi: zena pozice: ucetni plat: Zaznam tisk & pracujici zaznam.pracujici 44 jmeno: Jana pohlavi: zena pozice: ucetni plat: Zaznam tisk & pracujici P1 zaznam.pracujici 44 jmeno: Jana pohlavi: zena pozice: ucetni plat: Osoba klic: 44 jmeno: Jana pohlavi: zena Zaznam tisk & pracujici OSOBA zaznam.pracujici 44 jmeno: Jana pohlavi: zena pozice: ucetni plat:

50 Přetěžování metod Přetěžování metod Několik metod má stejné jméno Každá metoda má jinou množinu parametrů Počet parametrů Typ parametrů 50

51 // Overloaded method declarations. Poznámky public class MethodOverload { // test overloaded square methods public void testoverloadedmethods() { System.out.printf( "Square of integer 7 is %d\n", square( 7 ) ); System.out.printf( "Square of double 7.5 is %f\n", square( 7.5 ) ); // end method testoverloadedmethods // square method with int argument public int square( int intvalue ) { System.out.printf( "\ncalled square with int argument: %d\n", intvalue ); return intvalue * intvalue; // end method square with int argument // square method with double argument public double square( double doublevalue ) { System.out.printf( "\ncalled square with double argument: %f\n", doublevalue ); return doublevalue * doublevalue; // end method square with double argument // end class MethodOverload 51

52 // Application to test class MethodOverload. Poznámky public class MethodOverloadTest { public static void main( String args[] ) { MethodOverload methodoverload = new MethodOverload(); methodoverload.testoverloadedmethods(); // end main // end class MethodOverloadTest Called square with int argument: : 7 Square of integer 7 is 49 Called square with double argument: Square of double 7.5 is