Dědičnost

  • V realitě často vidíme, že objektové třídy jsou podtřídami, speciálními případy jiných:

    • všechny objekty podtřídy jsou zároveň objekty nadtřídy, např. každý objekt typu (třídy) ChovatelPsu je současně typu Clovek nebo

    • např. každý objekt typu (třídy) Pes je současně typu DomaciZvire

  • Někdy to chce realitu trochu zjednodušit, např. zde předpokládat, že v našem výseku reality neexistují psi "nedomácí".

  • Podtřída je tedy "zjemněním" nadtřídy — přebírá její vlastnosti a zpravidla přidává další, rozšiřuje svou nadtřídu/předka.

  • V Javě je každá uživatelem definovaná třída potomkem nějaké jiné — neuvedeme-li předka explicitně, je předkem vestavěná třída Object.

Terminologie dědičnosti

  • Nadtřídě (superclass) se také říká "bezprostřední předek", "rodičovská třída"

  • Podtřídě (subclass) se také říká "bezprostřední potomek", "dceřinná třída"

  • Dědění může mít i více "generací", např.

  • PersonEmployeeManager

  • Osoba je rodičovskou třídou zaměstnance, ten je rodičovskou třídou manažera.

  • Přeneseně tedy předkem (nikoli bezprostředním) manažera je člověk.

Jak zapisujeme dědění

  • Klíčovým slovem extends:

    public class Employee extends Person {
       // ... popis vlastností (proměnných, metod...)
       // zaměstnance navíc oproti (obecnému) člověku...
    }

Dědičnost a vlastnosti tříd (1)

Opakování:

  • Jak víme, třídy popisují skupiny objektů podobných vlastností.

  • Třídy mohou mít tyto skupiny vlastností :

    • Metody - procedury/funkce, které pracují (především) s objekty této třídy

    • Proměnné - pojmenované datové prvky (hodnoty) uchovávané v každém objektu této třídy

  • Vlastnosti jsou ve třídě "schované", tzv. zapouzdřené (encapsulated)

  • Třída připomíná záznam známý např. z Pascalu (record) nebo z C jako struct.

  • Záznamy však zapouzdřují jen proměnné, nikoli metody.

  • Co v tomto přináší dědičnost?

Dědičnost a vlastnosti tříd (2)

Dědičnost (alespoň v javovém smyslu) znamená, že dceřinná třída (podtřída, potomek):

  1. všechny vlastnosti (metody, proměnné) nadtřídy a

  2. přidává vlastnosti uvedené přímo v potomkovi

Příklad

  • Cíl: vylepšit třídu Account

  • Postup:

    • Zdokonalíme náš příklad s účtem tak, aby si účet "hlídal", kolik se z něj převádí peněz

    • Zdokonalenou verzi třídy Account nazveme CreditAccount

  • Vzorový zdroják samotný nepůjde přeložit, protože nemáme třídu, na níž závisí.

Příklad — zdrojový kód

public class CreditAccount extends Account {
   // private double balance; zdědí se z nadtřídy "Account"
   // zde pamatuji navíc, kolik mohu "jít do mínusu"
   private double creditLimit;
   public void add(double amount) {
      if (balance + creditLimit + amount >= 0) {
         // přes "super" zavoláme původní "neopatrnou" metodu
         super.add(amount);
      } else {
         System.err.println("Nelze odebrat částku " + (-amount));
      }
   }
   // writeInfo(), transferTo(Account to, double amount) se zdědí
}

Příklad — co tam bylo nového

  • Klíčové slovo extends značí, že třída CreditAccount je potomkem/podtřídou/rozšířením/dceřinnou třídou (subclass) třídy Account.

  • Konstrukce super.metoda(…); značí, že je volána metoda rodičovské třídy/předka/nadtřídy (superclass).

  • Kdyby se to super nepoužilo, zavolala by se metoda add třídy CreditAccount a program by se zacyklil!

Další příklad

Demoprojekt (viz IS) private_account:

  • výchozí třída Account

  • podědíme do třídy PrivateAccount, což je osobní/privátní účet

  • zde přibude nová vlastnost (proměnná "vlastník") nesoucí odkaz na osobu vlastnící tento účet.

Příklad na víceúrovňovou dědičnost

  • Neplést s vícenásobnou, ta v Javě není možná.

  • Více úrovněmi myslíme častou situaci, kdy ze třídy odvodíme podtřídu, z ní zase podtřídu…

Demoprojekt (viz IS) checked_private_account:

  • výchozí třída Account (obyčejný účet)

  • podědíme do třídy PrivateAccount (osobní/privátní účet)

  • z ní podědíme do třídy CheckedPrivateAccount (osobní účet s kontrolou minimálního zůstatku)