ITnetwork summer 2020
80 % bodů zdarma na online výuku díky naší Letní akci!
Pouze tento týden sleva až 80 % na e-learning týkající se PHP

8. diel - Aréna s mágom (dedičnosť a polymorfizmus)

V minulej lekcii, Dedičnosť a polymorfizmus , sme si vysvetlili dedičnosť a polymorfizmus. Dnes máme sľúbené, že si ich vyskúšame v praxi. Bude to opäť na našej aréne, kde z bojovníka oddědíme mága. Tento tutoriál už patrí k tým náročnejším a bude tomu tak aj u ďalších. Preto si priebežne precvičujte prácu s objektmi, skúšajte si naše cvičenia a tiež vymýšľajte nejaké svoje aplikácie, aby ste si zažili základné veci. To, že je tu prítomný celý seriál neznamená, že ho celý naraz prečítate a pochopíte :) Snažte sa programovať priebežne.

mág
Než začneme niečo písať, zhodneme sa na tom, čo by mal mág vedieť. Mág bude fungovať rovnako, ako bojovník. Okrem života bude mať však aj manu. Spočiatku bude mana plná. V prípade plnej many môže mág vykonať magický útok, ktorý bude mať pravdepodobne vyššie damage, ako útok normálne (ale samozrejme záleží na tom, ako si ho nastavíme). Tento útok manu vybije na 0. Každé kolo sa bude mana zvyšovať o 10 a mág bude podnikať len bežný útok. Akonáhle sa mana úplne doplní, opäť bude môcť magický útok použiť. Mana bude zobrazená grafickým ukazovateľom, rovnako ako život.

Vytvoríme teda triedu Mag.java, zdedíme ju z Bojovnik a dodáme ju atribúty, ktoré chceme oproti bojovníkovi navyše. Bude teda vyzerať takto (opäť si ju okomentujte):

class Mag extends Bojovnik {
    private int mana;
    private int maxMana;
    private int magickyUtok;
}

V mágovi nemáme zatiaľ prístup ku všetkým premenným, pretože sú v bojovníkovi nastavené ako privátne. Musíme triedu Bojovnik ľahko upraviť. Zmeníme modifikátory private u atribútov na protected. Budeme potrebovať len kocka a meno, ale pokojne nastavíme ako protected všetky atribúty charakteru, pretože sa v budúcnosti môžu hodiť, keby sme sa rozhodli oddědit ďalšie typy bojovníkov. Naopak atribút sprava nie je vhodné nastavovať ako protected, pretože nesúvisí s bojovníkom, ale s nejakou vnútornou logikou triedy. Trieda teda bude vyzerať nejako takto:

protected String jmeno;
protected int zivot;
protected int maxZivot;
protected int utok;
protected int obrana;
protected Kostka kostka;
private String zprava;

...

Prejdime ku konstruktoru.

Konštruktor potomka

Java nededia konstruktory! Je to pravdepodobne z toho dôvodu, že predpokladá, že potomok bude mať navyše nejaké atribúty a pôvodné konštruktor by u neho bol na škodu. To je aj náš prípad, pretože konštruktor mága bude brať oproti tomu z bojovníka navyše 2 parametre (mana a magický útok).

Definujeme si teda konštruktor v potomkovi, ktorý berie parametre potrebné pre vytvorenie bojovníka a niekoľko parametrov navyše pre mága.

O potomkov je nutné vždy volať konštruktor predka. Je to z toho dôvodu, že bez volania konstruktoru nemusí byť inštancie správne inicializovaná. Konštruktor predka nevoláme iba v prípade, že žiadny nemá. Náš konštruktor musia mať samozrejme všetky parametre potrebné pre predka plus tie nové, čo má navyše potomok. Niektoré potom odovzdáme predkovi a niektoré si spracujeme sami. Konštruktor predka sa vykoná pred naším konstruktoru.

V Jave existuje kľúčové slovo super, ktoré je podobné nami už známemu this. Na rozdiel od this, ktoré odkazuje na konkrétnu inštanciu triedy, super odkazuje na predka. My teda môžeme zavolať konštruktor predka s danými parametrami a potom vykonať navyše inicializáciu pre mága.

Konštruktor mága bude teda vyzerať takto:

public Mag(String jmeno, int zivot, int utok, int obrana, Kostka kostka, int mana, int magickyUtok) {
    super(jmeno, zivot, utok, obrana, kostka);
    this.mana = mana;
    this.maxMana = mana;
    this.magickyUtok = magickyUtok;
}

Pozn. rovnako môžeme volať aj iný konštruktor v tej istej triede (nie predka), len miesto super použijeme this.

Presuňme sa teraz do Arena.java a druhého bojovníka (Shadow) zmeňme na mága, napr. Takto:

Bojovnik gandalf = new Mag("Gandalf", 60, 15, 12, kostka, 30, 45);
Tento výukový obsah pomáhajú rozvíjať nasledujúce firmy, ktoré možno hľadajú práve teba!

Zmenu samozrejme musíme urobiť aj v riadku, kde bojovníka do arény vkladáme. Všimnite si, že mága ukladáme do premennej typu Bojovnik. Nič nám v tom nebráni, pretože bojovník je jeho predok. Rovnako tak si môžeme typ premennej zmeniť na Mag. Keď aplikáciu teraz spustíme, bude fungovať úplne rovnako, ako predtým. Mág všetko dedí z bojovníka a zatiaľ teda funguje ako bojovník.

Polymorfizmus a prepisovanie metód

Bolo by výhodné, keby objekt Arena mohol s mágom pracovať rovnako ako s bojovníkom. My už vieme, že takémuto mechanizmu hovoríme polymorfizmus. Aréna zavolá na objekte metódu útočí () so súperom v parametri. Nestará sa o to, či bude útok vykonávať bojovník alebo mág, bude s nimi pracovať rovnako. U mága si teda prepíšeme metódu útočí () z predka. Prepíšeme zdedenú metódu tak, aby útok pracoval s mannou, hlavička metódy však zostane rovnaká.

Keď sme pri metódach, budeme v Bojovnik.java ešte určite používať metódu nastavZpravu (), tá je však privátne. Označme ju ako protected:

protected void nastavZpravu(String zprava) {

Pozn. Pri návrhu bojovníka sme samozrejme mali myslieť na to, že sa z neho bude dediť a už označiť vhodné atribúty a metódy ako protected. V tutoriále k bojovníkovi som vás tým však nechcel zbytočne zaťažovať, preto musíme modifikátory zmeniť až teraz, kedy im rozumieme :)

Poďme prepísať Útočia () bojovníka v mágovi. Metódu normálne definujeme v Mag.java tak, ako sme zvyknutí, len ju označíme @Override:

@Override
public void utoc(Bojovnik souper) {

Podobne sme prepisovali metódu toString () u našich objektov, každý objekt v Jave je totiž odděděný od java.lang.Object, ktorý obsahuje niekoľko defaultných metód a jedna z nich je aj toString (). Pri jej implementácii by sme teda mali označiť, že sa jedná o prepísanou metódu.

Správanie metódy Útočia () nebude nijako zložité. Podľa hodnoty many buď vykonáme bežný útok alebo útok magický. Hodnotu many potom buď zvýšime o 10 alebo naopak znížime na 0 v prípade magického útoku.

@Override
public void utoc(Bojovnik souper) {
    int uder = 0;
    // Mana není naplněna
    if (mana < maxMana) {
        mana += 10;
        if (mana > maxMana) {
            mana = maxMana;
        }
        uder = utok + kostka.hod();
        nastavZpravu(String.format("%s útočí s úderem za %s hp", jmeno, uder));
    } else { // Magický útok
        uder = magickyUtok + kostka.hod();
        nastavZpravu(String.format("%s použil magii za %s hp", jmeno, uder));
        mana = 0;
    }
    souper.branSe(uder);
}

Kód je asi zrozumiteľný. Všimnite si obmedzenia many na Maxman, môže sa nám totiž stať, že túto hodnotu presiahne, keď ju zvyšujeme o 10. Keď sa nad kódom zamyslíme, tak útok vyššie v podstate vykonáva pôvodnej metóda útočí (). Iste by bolo prínosné zavolať podobu metódy na predkovi namiesto toho, aby sme správanie odpisovali. K tomu opäť použijeme super:

    @Override
    public void utoc(Bojovnik souper) {
    // Mana není naplněna
    if (mana < maxMana) {
    mana += 10;
    if (mana > maxMana) {
        mana = maxMana;
    }
    super.utoc(souper);
    } else { // Magický útok
    int uder = magickyUtok + kostka.hod();
    nastavZpravu(String.format("%s použil magii za %s hp", jmeno, uder));
    souper.branSe(uder);
    mana = 0;
    }
    }
import java.util.Random;
public class Kostka {
    private Random random;
    private int pocetSten;

    public Kostka() {
    pocetSten = 6;
    random = new Random();
    }

    public Kostka(int pocetSten) {
    this.pocetSten = pocetSten;
    random = new Random();
    }

    public int vratPocetSten() {
    return pocetSten;
    }

    public int hod() {
    return random.nextInt(pocetSten) + 1;
    }

    @Override
    public String toString() {
    return String.format("Kostka s %s stěnami", pocetSten);
    }
}
class Bojovnik {
    protected String jmeno;
    protected int zivot;
    protected int maxZivot;
    protected int utok;
    protected int obrana;
    protected Kostka kostka;
    private String zprava;

    public Bojovnik(String jmeno, int zivot, int utok, int obrana, Kostka kostka) {
    this.jmeno = jmeno;
    this.zivot = zivot;
    this.maxZivot = zivot;
    this.utok = utok;
    this.obrana = obrana;
    this.kostka = kostka;
    }

    public boolean nazivu() {
     return (zivot > 0);
    }

    public String grafickyZivot() {
    String s = "[";
    int celkem = 20;
    double pocet = Math.round(((double)zivot / maxZivot) * celkem);
    if ((pocet == 0) && (nazivu())) {
        pocet = 1;
    }
    for (int i = 0; i < pocet; i++) {
        s += "#";
    }
    for (int i = 0; i < celkem - pocet; i++) {
        s += " ";
    }
    s += "]";
    return s;
    }

    public void utoc(Bojovnik souper) {
    int uder = utok + kostka.hod();
    nastavZpravu(String.format("%s útočí s úderem za %s hp", jmeno, uder));
    souper.branSe(uder);
    }

    public void branSe(int uder) {
    int zraneni = uder - (obrana + kostka.hod());
    if (zraneni > 0) {
        zivot -= zraneni;
        zprava = String.format("%s utrpěl poškození %s hp", jmeno, zraneni);
        if (zivot <= 0) {
        zivot = 0;
        zprava += " a zemřel";
        }
    } else
        zprava = String.format("%s odrazil útok", jmeno);
        nastavZpravu(zprava);
    }

    protected void nastavZpravu(String zprava) {
    this.zprava = zprava;
    }

    public String vratPosledniZpravu() {
    return zprava;
    }

    @Override
    public String toString() {
    return jmeno;
    }

}
class Arena {
    private Bojovnik bojovnik1;
    private Bojovnik bojovnik2;
    private Kostka kostka;

    public Arena(Bojovnik bojovnik1, Bojovnik bojovnik2, Kostka kostka) {
    this.bojovnik1 = bojovnik1;
    this.bojovnik2 = bojovnik2;
    this.kostka = kostka;
    }

    private void vykresli() {
    System.out.println("-------------- Aréna -------------- \n");
    System.out.println("Zdraví bojovníků: \n");
    System.out.printf("%s %s\n", bojovnik1, bojovnik1.grafickyZivot());
    System.out.printf("%s %s\n", bojovnik2, bojovnik2.grafickyZivot());
    }

    private void vypisZpravu(String zprava) {
    System.out.println(zprava);
    try {
        Thread.sleep(500);
    } catch (InterruptedException ex) {
      System.err.println("Chyba, nepovedlo se uspat vlákno");
    }
    }

    public void zapas() {
    // původní pořadí
    Bojovnik b1 = bojovnik1;
    Bojovnik b2 = bojovnik2;
    System.out.println("Vítejte v aréně!");
    System.out.printf("Dnes se utkají %s s %s! \n\n", bojovnik1, bojovnik2);
    // prohození bojovníků
    boolean zacinaBojovnik2 = (kostka.hod() <= kostka.vratPocetSten() / 2);
    if (zacinaBojovnik2) {
        b1 = bojovnik2;
        b2 = bojovnik1;
    }
    System.out.printf("Začínat bude bojovník %s! \n\nZápas může začít...\n", b1);

    // cyklus s bojem
    while (b1.nazivu() && b2.nazivu()) {
        b1.utoc(b2);
        vykresli();
        vypisZpravu(b1.vratPosledniZpravu()); // zpráva o útoku
        vypisZpravu(b2.vratPosledniZpravu()); // zpráva o obraně
        if (b2.nazivu()) {
        b2.utoc(b1);
        vykresli();
        vypisZpravu(b2.vratPosledniZpravu()); // zpráva o útoku
        vypisZpravu(b1.vratPosledniZpravu()); // zpráva o obraně
        }
        System.out.println();
    }
    }
}

Opäť vidíme, ako môžeme znovupoužívat kód. S dedičnosťou je spojené naozaj mnoho techník, ako si ušetriť prácu. V našom prípade to ušetrí niekoľko riadkov, ale u väčšieho projektu by to mohlo mať obrovský význam.

Aplikácia teraz funguje tak, ako má.

Konzolová aplikácia
-------------- Aréna --------------

Zdraví bojovníků:

Zalgoren [#############       ]
Gandalf [#################   ]
Gandalf použil magii za 52 hp
Zalgoren utrpěl poškození 36 hp

Arena nás však neinformuje o mane mága, poďme to napraviť. Pridáme mágovi verejnú metódu grafickaMana (), ktorá bude obdobne ako u života vracať String s grafickým ukazovateľom many.

Aby sme nemuseli logiku so zložením ukazovatele písať dvakrát, upravíme metódu grafickyZivot () v Bojovnik.java. Pripomeňme si, ako vyzerá:

public String grafickyZivot() {
    String s = "[";
    int celkem = 20;
    double pocet = Math.round(((double)zivot / maxZivot) * celkem);
    if ((pocet == 0) && (nazivu())) {
        pocet = 1;
    }
    for (int i = 0; i < pocet; i++) {
        s += "#";
    }
        s = String.format("%1$-" + (celkem + 1) + "s", s);
    s += "]";
    return s;
}

Vidíme, že nie je výnimkou premenných zivot a maxZivot na živote nijako závislá. Metódu premenujeme na grafickyUkazatel a dáme ju 2 parametre: aktuálnu hodnotu a maximálnu hodnotu. zivot a maxZivot v tele metódy potom nahradíme za aktualne a maximalnu. Modifikátor bude protected, aby sme metódu mohli v potomkovi použiť:

protected String grafickyUkazatel(int aktualni, int maximalni) {
    String s = "[";
    int celkem = 20;
    double pocet = Math.round(((double)aktualni / maximalni) * celkem);
    if ((pocet == 0) && (nazivu())) {
        pocet = 1;
    }
    for (int i = 0; i < pocet; i++) {
        s += "#";
    }
        s = String.format("%1$-" + (celkem + 1) + "s", s);
    s += "]";
    return s;
}

Metódu grafickyZivot () v Bojovnik.java naimplementujeme znovu, bude nám v nej stačiť jediný riadok a to zavolanie metódy grafickyUkazatel () s príslušnými parametrami:

public String grafickyZivot() {
    return grafickyUkazatel(zivot, maxZivot);
}

Určite som mohol v tutoriálu s bojovníkom urobiť metódu grafickyUkazatel () rovno. Chcel som však, aby sme si ukázali, ako sa rieši prípady, keď potrebujeme vykonať podobnú funkčnosť viackrát. S takouto parametrizáciou sa v praxi budete stretávať často, pretože nikdy presne nevieme, čo budeme v budúcnosti od nášho programu požadovať.

Teraz môžeme vykresľovať ukazovateľ tak, ako sa nám to hodí. Presuňme sa do Mag.java a naimplementujme metódu grafickaMana ():

public String grafickaMana() {
    return grafickyUkazatel(mana, maxMana);
}

Jednoduché, že? Teraz je mág hotový, zostáva len naučiť arénu zobrazovať manu v prípade, že je bojovník mág. Presuňme sa teda do Arena.

Rozpoznanie typu objektu

Keďže sa nám teraz vykreslenie bojovníka skomplikovalo, urobíme si na neho samostatnú metódu vypisBojovnika (), jej parametrom bude daná inštancie bojovníka:

private void vypisBojovnika(Bojovnik b) {
    System.out.println(b);
    System.out.print("Zivot: ");
    System.out.println(b.grafickyZivot());
}

Teraz poďme reagovať na to, či je bojovník mág. Minule sme si povedali, že k tomu slúži operátor instanceof:

private void vypisBojovnika(Bojovnik b) {
    System.out.println(b);
    System.out.print("Zivot: ");
    System.out.println(b.grafickyZivot());
    if (b instanceof Mag) {
        System.out.print("Mana:  ");
        System.out.println(((Mag)b).grafickaMana());
    }
}

Bojovníka sme museli na mága pretypovať, aby sme sa k metóde grafickaMana () dostali. Samotný Bojovnik ju totiž nemá. To by sme mali, vypisBojovnika budeme volať v metóde vykresli (), ktorá bude vyzerať takto:

    private void vykresli() {
    System.out.println("-------------- Aréna -------------- \n");
    System.out.println("Bojovníci: \n");
    vypisBojovnika(bojovnik1);
    System.out.println();
    vypisBojovnika(bojovnik2);
    System.out.println();
    }
class Bojovnik {
    protected String jmeno;
    protected int zivot;
    protected int maxZivot;
    protected int utok;
    protected int obrana;
    protected Kostka kostka;
    private String zprava;

    public Bojovnik(String jmeno, int zivot, int utok, int obrana, Kostka kostka) {
    this.jmeno = jmeno;
    this.zivot = zivot;
    this.maxZivot = zivot;
    this.utok = utok;
    this.obrana = obrana;
    this.kostka = kostka;
    }

    public boolean nazivu() {
     return (zivot > 0);
    }

    protected String grafickyUkazatel(int aktualni, int maximalni) {
    String s = "[";
    int celkem = 20;
    double pocet = Math.round(((double)aktualni / maximalni) * celkem);
    if ((pocet == 0) && (nazivu())) {
        pocet = 1;
    }
    for (int i = 0; i < pocet; i++) {
        s += "#";
    }
    s = String.format("%1$-" + (celkem + 1) + "s", s);
    s += "]";
    return s;
    }

    public String grafickyZivot() {
    return grafickyUkazatel(zivot, maxZivot);
    }

    public void utoc(Bojovnik souper) {
    int uder = utok + kostka.hod();
    nastavZpravu(String.format("%s útočí s úderem za %s hp", jmeno, uder));
    souper.branSe(uder);
    }

    public void branSe(int uder) {
    int zraneni = uder - (obrana + kostka.hod());
    if (zraneni > 0) {
         zivot -= zraneni;
         zprava = String.format("%s utrpěl poškození %s hp", jmeno, zraneni);
         if (zivot <= 0) {
         zivot = 0;
         zprava += " a zemřel";
         }
    } else
        zprava = String.format("%s odrazil útok", jmeno);
        nastavZpravu(zprava);
    }

    protected void nastavZpravu(String zprava) {
    this.zprava = zprava;
    }

    public String vratPosledniZpravu() {
    return zprava;
    }

    @Override
    public String toString() {
    return jmeno;
    }
}
class Mag extends Bojovnik {
    private int mana;
    private int maxMana;
    private int magickyUtok;

    public Mag(String jmeno, int zivot, int utok, int obrana, Kostka kostka, int mana, int magickyUtok)
    {
    super(jmeno, zivot, utok, obrana, kostka);
    this.mana = mana;
    this.maxMana = mana;
    this.magickyUtok = magickyUtok;
    }

    @Override
    public void utoc(Bojovnik souper) {
    // Mana není naplněna
    if (mana < maxMana) {
         mana += 10;
         if (mana > maxMana) {
         mana = maxMana;
        }
         super.utoc(souper);
    } else { // Magický útok
         int uder = magickyUtok + kostka.hod();
         nastavZpravu(String.format("%s použil magii za %s hp", jmeno, uder));
         souper.branSe(uder);
         mana = 0;
    }
    }

     public String grafickaMana() {
    return grafickyUkazatel(mana, maxMana);
    }
}


Hotovo :)

Konzolová aplikácia
-------------- Aréna --------------

Bojovníci:

Zalgoren
Život: [##########          ]

Gandalf
Život: [#####               ]
Mana: [#############       ]

Zalgoren útočí s úderem za 28 hp

Aplikáciu ešte môžeme dodať krajší vzhľad, vložil som ASCIIart nadpis Aréna, ktorý som vytvoril touto aplikáciou: http://patorjk.com/software/taag. Metódu k vykreslenie ukazovatele som upravil tak, aby vykreslovala plný obdĺžnik miesto # (ten napíšete pomocou Alt + 219). Výsledok môže vyzerať takto:

Konzolová aplikácia
   __    ____  ____  _  _    __
  /__\  (  _ \( ___)( \( )  /__\
 /(__)\  )   / )__)  )  (  /(__)\
(__)(__)(_)\_)(____)(_)\_)(__)(__)

Bojovníci:

Zalgoren
Život: ████

Gandalf
Život: ███████
Mana:  █

Gandalf použil magii za 48 hp
Zalgoren utrpěl poškození 33 hp

Kód máte v prílohe. Ak ste niečomu nerozumeli, skúste si článok prečítať viackrát alebo pomalšie, sú to dôležité praktiky. V budúcej lekcii, Riešené úlohy k 5. - 8. lekciu OOP v Jave , si vysvetlíme pojem statika.

V nasledujúcom cvičení, Riešené úlohy k 5. - 8. lekciu OOP v Jave, si precvičíme nadobudnuté skúsenosti z predchádzajúcich lekcií.


 

Stiahnuť

Stiahnuté 1145x (31.13 kB)
Aplikácia je vrátane zdrojových kódov v jazyku java

 

Predchádzajúci článok
Dedičnosť a polymorfizmus
Všetky články v sekcii
Objektovo orientované programovanie v Jave
Článok pre vás napísal David Čápka
Avatar
Ako sa ti páči článok?
Ešte nikto nehodnotil, buď prvý!
Autor pracuje jako softwarový architekt a pedagog na projektu ITnetwork.cz (a jeho zahraničních verzích). Velmi si váží svobody podnikání v naší zemi a věří, že když se člověk neštítí práce, tak dokáže úplně cokoli.
Unicorn College Autor sa informačné technológie naučil na Unicorn College - prestížnej súkromnej vysokej škole IT a ekonómie.
Aktivity (1)

 

 

Komentáre

Avatar
David Čápka
Tým ITnetwork
Avatar
David Čápka:24.4.2018 19:07

Máš pravdu, moje chyba, Java má tohle dost nešikovně nastavené. Pokud bys chtěla atributy nebo metody zpřístupnit pouze potomkům, nepíše se před ně žádný modifikátor přístupu. Je to potom něco mezi private a protected. Doplním to tam.

Odpovedať
24.4.2018 19:07
Jsem moc rád, že jsi na síti, a přeji ti top IT kariéru, ať jako zaměstnanec nebo podnikatel. Máš na to! :)
Avatar
Odpovedá na David Čápka
Radka Jánská:24.4.2018 22:13

Dekuju za vysvetleni. Je toho hodne, zvlast na zacatecnika jako ja, je jasne, ze zadne materialy nemuzou obsahovat vsechny informace... Moc ocenuju tvou rychlou odpoved.

 
Odpovedať
24.4.2018 22:13
Avatar
patrik.hrnciar:5.5.2018 13:34

Ahoj, v metode grafickyUkazatel v casti :
if ((pocet == 0) && (nazivu())) {
pocet = 1;
}
v pripade Maga bude v ukazovateli many vzdy minimalne 1 dielik aj ked bude mana = 0 , a mag bude nazive.

 
Odpovedať
5.5.2018 13:34
Avatar
Lubor Pešek
Člen
Avatar
Lubor Pešek:12.7.2018 9:58

O potomků je nutné vždy volat konstruktor předka. Je to z toho důvodu, že bez volání konstruktoru nemusí být instance správně inicializovaná. Konstruktor předka nevoláme pouze v případě, že žádný nemá. Náš konstruktor musí mít samozřejmě všechny parametry potřebné pro předka plus ty nové, co má navíc potomek. Některé potom předáme předkovi a některé si zpracujeme sami. Konstruktor předka se vykoná před naším konstruktorem.

To není úplně tak pravda.
Pokud voláš konstruktor předka, tak ten se inicializuje vždy "správně":)
Logika dědičnosti a proč se musí volat konstruktor předka spočívá v tom, že i když to tak nevypadá, tak my když voláme jakéhokoliv potomka, tak JVM v pozadí vytvoří i instance všech předků, ze kterých potom voláme překryté nebo zděděné metody tak, že my sice nevidíme, že to volá předek, ale je to tak.

V podstatě tato rekurze vytváření instancí na pozadí končí až u kořenové třídy všech tříd - Objektu.
Příklad: Vytvořím si třídu A a B. Třída B bude dědit z A. Jenže (a to si moc lidí hned tak neuvědomí) i třída A dědí. A dědí z Object class. (Object třída je jediná třída, která nedědí od nikoho).
Takže My můžeme vytvořit třeba i bezparametrický konstruktor u tříd A a B a následně vytvoříme novou instanci třídy B. JVM ovšem na pozadí vytvoří nejdřív novou instanci Object, potom novou instanci A a až potom instanci B.
A u parametrických tříd je to úplně to samé. Vždy volám aspoň jeden z konstruktorů předka - právě aby se vůbec mohlo z něčeho dědit.
U implicitních konstruktorů je jediná výjimka, protože ty jsou defaultně skryté, takže je není třeba definovat. Kdyby to tak nebylo, tak i když bychom si vytvořili úplně novou samostatnou třídu, tak bychom museli vždy psát:

public class newClass extends Object {
        public newClass() {
                super(); // <---- odkazuje (dědí) ze třídy Object a proto je třeba vytvořit bezparametrický konstruktor. Object jiný nemá
        }
}
Editované 12.7.2018 9:59
Odpovedať
12.7.2018 9:58
Existují dva způsoby, jak vyřešit problém. Za prvé vyhoďte počítač z okna. Za druhé vyhoďte okna z počítače.
Avatar
Jiří Satora:30.12.2018 12:17

Na mě je to moc složité. Ani jsem to nepřečetl celé. :-###

 
Odpovedať
30.12.2018 12:17
Tento výukový obsah pomáhajú rozvíjať nasledujúce firmy, ktoré možno hľadajú práve teba!
Avatar
Jozef Tomašec:18.2.2019 21:11

Popravde som sa v tej dedičnosti trocha stratil. Možno, keby bol priklad pisany rovno od zaciatku, ale pri tom prepisovani jednotlivych prikazov mi to prišlo komplikovanejšie.

 
Odpovedať
18.2.2019 21:11
Avatar
Odpovedá na patrik.hrnciar
Karel Stehlík:26.7.2019 20:02

Tak si tu podmínku v metodě "grafickyUkazatel" ve třídě "Bojovnik" změň takto:

if ((pocet == 0) && (nazivu()) && (aktualni != 0))

Když to v podmínce projde až k tomu parametru metody "aktualni", je jasné, že v případě hodnoty 0 musí jít o manu, jinak by se podmínka ukončila už při testování metody "nazivu()", která by v případě nulového života byla false.

 
Odpovedať
26.7.2019 20:02
Avatar
Michal Richter:13.9.2019 14:18

Chybička v textu, místo Arena.java má být Program.java:
"Přesuňme se nyní do Program.java a druhého bojovníka (Shadow) změňme na mága, např. takto:"

 
Odpovedať
13.9.2019 14:18
Avatar
Gemy
Člen
Avatar
Gemy:24. mája 17:07

Nějaké vysvětlení prosím pro formát(%1$-) ?

Odpovedať
24. mája 17:07
Peníze neznamenají úspěch.
Avatar
Gemy
Člen
Avatar
Odpovedá na Gemy
Gemy:24. mája 18:15

Už jsem pochopil format() ... bože to je těžká bodel :-D

String s = "X";
System.out.printf("%-"+(s.length()+1)+"s&%<"+(s.length()+1)+"s\n", s);
Odpovedať
24. mája 18:15
Peníze neznamenají úspěch.
Robíme čo je v našich silách, aby bola tunajšia diskusia čo najkvalitnejšia. Preto do nej tiež môžu prispievať len registrovaní členovia. Pre zapojenie sa do diskusie sa zaloguj. Ak ešte nemáš účet, zaregistruj sa, je to zadarmo.

Zatiaľ nikto nevložil komentár - buď prvý!