class Subclass extends Superclass
Tomáš Pitner, Radek Ošlejšek, Marek Šabo
Dědičnost. Nejlepší objektově-orientovaný způsob, jak zbohatnout.
Objektové třídy jsou obvykle podtřídami, tj. speciálními případy jiných tříd:
class Subclass extends Superclass
class DogKeeper extends Person {
// methods & attributes for DogKeeper
// in addition to Person
}
Všechny objekty typu DogKeeper
jsou současně typu Person
.
Person p = new DogKeeper("Karel");
V Javě dědí každá třída od třídy |
Nadtřída = superclass, "bezprostřední předek", "rodičovská třída"
Podtřída = subclass, "bezprostřední potomek", "dceřinná třída"
je specializací své nadtřídy
přebírá vlastnosti nadtřídy
zpravidla přidává další vlastnosti, čímž nadtřídu rozšiřuje (extends
)
Dědičnost by měla splňovat vztah je (is a) — Chovatel psa je osoba.
Při atributech třídy se používá vztah má (has a) — Osoba má jméno.
Abychom zohlednili konceptuální vztah obecnější vs. speciálnější typ.
Abychom se vyhnuli opakování kódu a dosáhli znovupoužití (= kód metod a atributů se podědí, nemusíme jej znovu psát).
Mělo by platit oboje, aby mělo smysl dědičnost použít.
Dědění může být vícegenerační:
public class Manager extends Employee { ... }
public class Employee extends Person { ... }
Manažer podědí metody a atributy ze třídy Zaměstnanec i Osoba.
Java vícenásobnou dědičnost u tříd nepodporuje!
Důvodem je problém typu diamant:
class DoggyManager extends Employee, DogKeeper { }
class Employee { public String toString() { "Employee"; } }
class DogKeeper { public String toString() { "DogKeeper"; } }
DoggyManager().toString(); // we have a problem!
Vícenásobná dědičnost je možná jedině u rozhraní (metody zatím nemají definovanou implementaci).
Dědičnost (v kontextu Javy) znamená:
potomek dědí všechny vlastnosti nadtřídy
poděděné vlastnosti potomka se mohou změnit (např. překrytím metody)
potomek může přidat další vlastnosti
Pozn.: Vlastnosti třídy = metody & atributy třídy
vyhýbáme se duplikaci kódu
kód je kratší
když potřebuji upravit předka, musím upravit změny ve všech potomcích, co může být netriviální
méně závislostí, více kódu
více používné v praxi
Account
Vylepšíme třídu Account
tak, aby zůstatek nebyl nižší než minimální zůstatek
Realizujeme tedy změnu metody debit
pomocí jejího překrytí (overriding)
Stará třída Account
:
public class Account implements Informing {
private int balance;
...
public boolean debit(int amount) {
if(amount <= 0) return false;
balance -= amount;
return true;
}
}
CheckedAccount
public class CheckedAccount extends Account {
private int minimalBalance;
public CheckedAccount(Person owner, int minBal, int initBal) {
super(owner, initBal); // calling Account constructor
if(initBal < minBal) { // is initial balance sufficient?
throw new IllegalArgumentException("low initial balance");
}
this.minimalBalance = minBal;
}
@Override
public boolean debit(int amount) {
// check min. balance
if(getBalance() - amount >= minimalBalance) {
return super.debit(amount); // the debit is deducted
} else return false;
}
}
Klíčové slovo extends
značí, že třída CheckedAccount
je potomkem (subclass) třídy Account
.
Konstrukce super.metoda(…);
značí, že je volána metoda předka, tedy třídy Account
.
Kdyby se super
nepoužilo, zavolala by se metoda debit
třídy CheckedAccount
a program by se zacyklil!
V konstruktoru potomka je vždy nutno zavolat konstruktor předka, protože se v něm inicializují vlastnosti dané třídy. |
Konstruktor předka je nutno zavolat jako první, protože by se pak dali použít vlastnosti, které zatím nejsou nainicializované. |
Často se používá skládání (kompozice) objektů, kdy objekt nedědí, ale nese odkaz na jiný objekt.
public class CheckedAccount {
private int minimalBalance;
private Account account;
public CheckedAccount(Person owner, int minBal, int initBal) {
account = new Account(owner, initBal);
...
}
// account.debit(amount)
}
Kompozicí se zabývá navazující kurz PV168 Seminář Javy.