Cílem objektového programování je rozdělení aplikace na více malých problémů, které jsou jednoduše řešitelné, v lepším případě dokonce již vyřešené. V dnešním díle bude řeč zejména o dědičnosti objektů.

Dědičnost

Dědičnost je jeden z hlavních principů objektově orientovaného programování. Jeho základní myšlenka spočívá v následujícím principu: každá třída má svého předchůdce, po kterém dědí veškeré proměnné a metody.

V Javě má každá třída právě jednoho předchůdce (na rozdíl např. od C++). Každá třída obsahuje všechny veřejné proměnné i funkce, které obsahovala původní třída. K nim může dodefinovat nové proměnné a funkce. Dědičností (vztahem otec-syn) jsou třídy uspořádány do stromové struktury, kde na vrcholu stromu je třída Object (ta je v Javě jedinou třídou, která nemá předchůdce a všechny třídy jsou jejími přímými nebo nepřímými následníky).

Dědičnost se deklaruje pomocí klíčového slova extends uvedeného za jménem třídy. Pokud není uvedeno, je deklarovaná třída následníkem třídy Object.

soubor Osoba.java:

// třída Osoba dědí od třídy Object  public class Osoba {
  public String jmeno;
  public String rodne_cislo;
  public Osoba(String jmeno, String rodne_cislo) {
    this.jmeno = jmeno;
    this.rodne_cislo = rodne_cislo;
    }
  public Osoba(String jmeno) {
    this.jmeno = jmeno;
    this.rodne_cislo = “;
    }
}

soubor Zamestnanec.java:

// třída Zamestnanec dědí od třídy Osoba
public class Zamestnanec extends Osoba {
  public int plat;
  public Zamestnanec(String jmeno, String rodne_cislo, int plat) {
    super (jmeno, rodne_cislo);
    this.plat = plat;
  }
  public Zamestnanec(String jmeno, int plat) {
    super (jmeno);
    this.plat = plat;
  }
}

Třída Zamestnanec dědí od třídy Osoba veškeré vlastnosti a proměnné, k nim si přidává proměnnou plat. Ve svých konstruktorech volá konstruktor třídy Osoba (ten nastaví proměnné jmeno a rodne_cislo) a pak nastaví proměnnou plat.

Síla objektově orientovaného programování spočívá právě v možnosti použít existující třídu a té pouze upravit popř. přidat několik metod a zbytek ponechat.

Každý objekt zděděného typu je rovněž plnohodnotným objektem typu otcovského a je ho možné ukládat do proměnných takového typu.

Osoba z = new Zamestnanec();

Přepisování metod

Následující vlastnosti se ve světě objektového programování říká polymorfismus. Předpokládejme, že máme třídu A a třídu B, která od A dědí. V třídě A definujeme funkci s názvem fce, ve třídě B pak tuto metodu přepíšeme metodou stejného jména a stejných parametrů. Pokud nyní založíme objekt typu B a vyvoláme metodu fce, spustí se metoda objektu B i v případě, že je objekt uložen v proměnné typu A. Ilustruje to následující příklad:

soubor Osoba.java:

public class Osoba {
  public int fce () {
    return 10;
    }
  …
}

soubor Zamestnanec.java:

public class Zamestnanec extends Osoba {
  public int fce () {
    return 20;
    }

}

jiný soubor:

Zamestnanec a = new Zamestnanec();
Osoba b = new Zamestnanec();
Osoba c = new Osoba();
System.out.println (a.fce());      // vypíše 20
System.out.println (b.fce());      // vypíše 20
System.out.println (c.fce());      // vypíše 10

Kompilátor Javy přitom v době kompilace nemůže vědět, zda v proměnné b (typu Osoba) je uložen objekt typu Osoba nebo objekt nějaké jeho podtřídy. Která metoda bude ve skutečnosti spuštěna se proto rozhoduje až dynamicky za běhu programu.

Praktický příklad

Další příklad polymorfismu, který uvedu, je z praxe a je velice intuitivní.

Prvky uživatelského rozhraní (tlačítka, editační boxy, Comboboxy apod.) jsou všechny potomky třídy Component. Každé okno si uchovává jejich seznam, ale předem neví, jaké komponenty v bude okno obsahovat (můžeme si dokonce díky dědičnosti vytvořit vlastní komponenty). Jedná se tedy o seznam položek typu Component.

Když má být okno překresleno, je potřeba překreslit všechny komponenty, proto se pro každou komponentu na seznamu zavolá metoda repaint (tato metoda je zděděná od objektu Component). Java tedy pro každou komponentu za běhu zjistí její typ a podle toho spustí patřičnou metodu repaint – Button.repaint(), ComboBox.repaint(), MojeKomponenta.repaint(), … Každá komponenta přitom kreslí něco jiného a tyto metody jsou tedy různé.

Modifikátory viditelnosti

Možná jste si v předchozích dílech všimli klíčového slova public. Jedná se o modifikátor viditelnosti, který označuje, že je daná třída, metoda či proměnná veřejná, tedy viditelná odkudkoli ze zdrojového kódu. Pokud proměnnou či metodu definujete jako privat (soukromou), bude přístupná pouze z jiných metod téhož objektu.

Dalšími modifikátory viditelnosti jsou protected, privat protected a implicitní modifikátor viditelnosti (pokud neuvedete nic). Úroveň jejich viditelnosti je mezi public a privat. Pro běžné programování myslím není nutné ho přesně znát, pokud vás zajímá, naleznete ho v oficiální dokumentaci Javy (na serveru java.sun.com).

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

3 Příspěvků v diskuzi

  1. Ahoj,
    učím se Javu a potřeboval bych trochu poradit. Zabývám se teď dědičností.
    Dělám si projekt,který se skládá:
    // nadtřída
    class Vehicle { atd.

    // podtřída (potomek) Auto bázové třídy Vehicle
    Class Auto Extends Vehicle { atd.

    public class ExtendsVehicleDemo {
    public static void main (String[] args) {
    atd.
    Problém je v tom,že když chci do svého projektu vložit podtřídu „class Auto extends Vehicle“,tak mi to nejde.
    Napíši class pak začnu psát Auto a objeví se mi chybný název třídy.
    Poraďte mi prosím,jak mohu do svého projektu vložit podtřídu “ class Auto extends Vehicle“.
    Pro programování v Javě použím Net Beans Ide.
    Děkuji. S pozdravem Jiří Kalina.

Odpovědět