Pouze tento týden sleva až 80 % na e-learning týkající se Javy. A zároveň využij akce až 30 % zdarma při nákupu e-learningu - Více informací.
Hledáme koordinátorku kurzů a programátora, 100% home office, 100% flexibilní. Prozkoumej aktuální pozice
Java week

Lekce 8 - Aréna s mágem (dědičnost a polymorfismus)

V minulé lekci, Dědičnost a polymorfismus, jsme si vysvětlili dědičnost a polymorfismus.

Dnes máme slíbeno, že si je vyzkoušíme v praxi. Bude to opět na naší aréně, kde z bojovníka oddědíme mága. Tento tutoriál již patří k těm náročnějším a bude tomu tak i u dalších. Proto si průběžně procvičujte práci s objekty, zkoušejte si naše cvičení a také vymýšlejte nějaké své aplikace, abyste si zažili základní věci. To, že je tu přítomen celý seriál neznamená, že ho celý najednou přečtete a pochopíte :) Snažte se programovat průběžně.

Mág

Než začneme něco psát, shodněme se na tom, co by měl mág umět. Mág bude fungovat stejně, jako bojovník. Kromě života bude mít však i manu. Zpočátku bude mana plná. V případě plné many může mág vykonat magický útok, který bude mít pravděpodobně vyšší damage, než útok normální (ale samozřejmě záleží na tom, jak si ho nastavíme). Tento útok manu vybije na 0. Každé kolo se bude mana zvyšovat o 10 a mág bude podnikat jen běžný útok. Jakmile se mana zcela doplní, opět bude moci magický útok použít. Mana bude zobrazena grafickým ukazatelem, stejně jako život.

Vytvoříme tedy třídu Mag.java, zdědíme ji z Bojovnik a dodáme ji atributy, které chceme oproti bojovníkovi navíc. Bude tedy vypadat takto (opět si ji okomentujte):

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

V mágovi nemáme zatím přístup ke všem proměnným, protože jsou v bojovníkovi nastavené jako privátní. Musíme třídu Bojovnik lehce upravit. Změníme modifikátory private u atributů na protected. Budeme potřebovat jen kostka a jmeno, ale klidně nastavíme jako protected všechny atributy charakteru, protože se v budoucnu mohou hodit, kdybychom se rozhodli oddědit další typy bojovníků. Naopak atribut zprava není vhodné nastavovat jako protected, protože nesouvisí s bojovníkem, ale s nějakou vnitřní logikou třídy. Třída tedy bude vypadat nějak takto:

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

...

Přejděme ke konstruktoru.

Konstruktor potomka

Java nedědí konstruktory! Je to pravděpodobně z toho důvodu, že předpokládá, že potomek bude mít navíc nějaké atributy a původní konstruktor by u něj byl na škodu. To je i náš případ, protože konstruktor mága bude brát oproti tomu z bojovníka navíc 2 parametry (mana a magický útok).

Definujeme si tedy konstruktor v potomkovi, který bere parametry potřebné pro vytvoření bojovníka a několik parametrů navíc pro mága.

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.

V Javě existuje klíčové slovo super, které je podobné námi již známému this. Na rozdíl od this, které odkazuje na konkrétní instanci třídy, super odkazuje na předka. My tedy můžeme zavolat konstruktor předka s danými parametry a poté vykonat navíc inicializaci pro mága.

Konstruktor mága bude tedy vypadat 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. stejně můžeme volat i jiný konstruktor v té samé třídě (ne předka), jen místo super použijeme this.

Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

Přesuňme se nyní do Arena.java a druhého bojovníka (Shadow) změňme na mága, např. takto:

Bojovnik gandalf = new Mag("Gandalf", 60, 15, 12, kostka, 30, 45);

Změnu samozřejmě musíme udělat i v řádku, kde bojovníka do arény vkládáme. Všimněte si, že mága ukládáme do proměnné typu Bojovnik. Nic nám v tom nebrání, protože bojovník je jeho předek. Stejně tak si můžeme typ proměnné změnit na Mag. Když aplikaci nyní spustíme, bude fungovat úplně stejně, jako předtím. Mág vše dědí z bojovníka a zatím tedy funguje jako bojovník.

Polymorfismus a přepisování metod

Bylo by výhodné, kdyby objekt Arena mohl s mágem pracovat stejným způsobem jako s bojovníkem. My již víme, že takovémuto mechanismu říkáme polymorfismus. Aréna zavolá na objektu metodu utoc() se soupeřem v parametru. Nestará se o to, jestli bude útok vykonávat bojovník nebo mág, bude s nimi pracovat stejně. U mága si tedy přepíšeme metodu utoc() z předka. Přepíšeme zděděnou metodu tak, aby útok pracoval s manou, hlavička metody však zůstane stejná.

Když jsme u metod, budeme v Bojovnik.java ještě jistě používat metodu nastavZpravu(), ta je však privátní. Označme ji jako protected:

protected void nastavZpravu(String zprava) {

Pozn. Při návrhu bojovníka jsme samozřejmě měli myslet na to, že se z něj bude dědit a již označit vhodné atributy a metody jako protected. V tutoriálu k bojovníkovi jsem vás tím však nechtěl zbytečně zatěžovat, proto musíme modifikátory změnit až teď, kdy jim rozumíme :)

Pojďme přepsat utoc() bojovníka v mágovi. Metodu normálně definujeme v Mag.java tak, jak jsme zvyklí, pouze ji označíme @Override:

@Override
public void utoc(Bojovnik souper) {

Podobně jsme přepisovali metodu toString() u našich objektů, každý objekt v Javě je totiž odděděný od java.lang.Object, který obsahuje několik defaultních metod a jedna z nich je i toString(). Při její implementaci bychom tedy měli označit, že se jedná o přepsanou metodu.

Chování metody utoc() nebude nijak složité. Podle hodnoty many buď provedeme běžný útok nebo útok magický. Hodnotu many potom buď zvýšíme o 10 nebo naopak snížíme na 0 v případě 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 srozumitelný. Všimněte si omezení many na maxMana, může se nám totiž stát, že tuto hodnotu přesáhneme, když ji zvyšujeme o 10. Když se nad kódem zamyslíme, tak útok výše v podstatě vykonává původní metoda utoc(). Jistě by bylo přínosné zavolat podobu metody na předkovi místo toho, abychom chování opisovali. K tomu opět 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ět vidíme, jak můžeme znovupoužívat kód. S dědičností je spojeno opravdu mnoho technik, jak si ušetřit práci. V našem případě to ušetří několik řádků, ale u většího projektu by to mohlo mít obrovský význam.

Aplikace nyní funguje tak, jak má.

Konzolová aplikace
-------------- 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 maně mága, pojďme to napravit. Přidáme mágovi veřejnou metodu grafickaMana(), která bude obdobně jako u života vracet String s grafickým ukazatelem many.

Abychom nemuseli logiku se složením ukazatele psát dvakrát, upravíme metodu grafickyZivot() v Bojovnik.java. Připomeňme si, jak vypadá:

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 není kromě proměnných zivot a maxZivot na životě nijak závislá. Metodu přejmenujeme na grafickyUkazatel a dáme ji 2 parametry: aktuální hodnotu a maximální hodnotu. zivot a maxZivot v těle metody poté nahradíme za aktualni a maximalni. Modifikátor bude protected, abychom metodu mohli v potomkovi použít:

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;
}

Metodu grafickyZivot() v Bojovnik.java naimplementujeme znovu, bude nám v ní stačit jediný řádek a to zavolání metody grafickyUkazatel() s příslušnými parametry:

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

Určitě jsem mohl v tutoriálu s bojovníkem udělat metodu grafickyUkazatel() rovnou. Chtěl jsem však, abychom si ukázali, jak se řeší případy, kdy potřebujeme vykonat podobnou funkčnost vícekrát. S takovouto parametrizací se v praxi budete setkávat často, protože nikdy přesně nevíme, co budeme v budoucnu od našeho programu požadovat.

Nyní můžeme vykreslovat ukazatel tak, jak se nám to hodí. Přesuňme se do Mag.java a naimplementujme metodu grafickaMana():

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

Jednoduché, že? Nyní je mág hotový, zbývá jen naučit arénu zobrazovat manu v případě, že je bojovník mág. Přesuňme se tedy do Arena.

Rozpoznání typu objektu

Jelikož se nám nyní vykreslení bojovníka zkomplikovalo, uděláme si na něj samostatnou metodu vypisBojovnika(), jejím parametrem bude daná instance bojovníka:

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

Nyní pojďme reagovat na to, jestli je bojovník mág. Minule jsme si řekli, že k tomu slouží 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 jsme museli na mága přetypovat, abychom se k metodě grafickaMana() dostali. Samotný Bojovnik ji totiž nemá. To bychom měli, vypisBojovnika budeme volat v metodě vykresli(), která bude vypadat 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á aplikace
-------------- Aréna --------------

Bojovníci:

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

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

Zalgoren útočí s úderem za 28 hp

Aplikaci ještě můžeme dodat hezčí vzhled, vložil jsem ASCIIart nadpis Aréna, který jsem vytvořil touto aplikací: http://patorjk.com/software/taag . Metodu k vykreslení ukazatele jsem upravil tak, aby vykreslovala plný obdelník místo # (ten napíšete pomocí Alt + 219). Výsledek může vypadat takto:

Konzolová aplikace
   __    ____  ____  _  _    __
  /__\  (  _ \( ___)( \( )  /__\
 /(__)\  )   / )__)  )  (  /(__)\
(__)(__)(_)\_)(____)(_)\_)(__)(__)

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 příloze. Pokud jste něčemu nerozuměli, zkuste si článek přečíst vícekrát nebo pomaleji, jsou to důležité praktiky.

V následujícím cvičení, Řešené úlohy k 5. - 8. lekci OOP v Javě, si procvičíme nabyté zkušenosti z předchozích lekcí.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 1202x (7.12 kB)
Aplikace je včetně zdrojových kódů v jazyce Java

 

Předchozí článek
Dědičnost a polymorfismus
Všechny články v sekci
Objektově orientované programování v Javě
Přeskočit článek
(nedoporučujeme)
Řešené úlohy k 5. - 8. lekci OOP v Javě
Článek pro vás napsal David Čápka
Avatar
Uživatelské hodnocení:
54 hlasů
David je zakladatelem ITnetwork a programování se profesionálně věnuje 13 let. Má rád Nirvanu, sushi a svobodu podnikání.
Unicorn university David se informační technologie naučil na Unicorn University - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity

 

 

Komentáře
Zobrazit starší komentáře (62)

Avatar
Gemy
Člen
Avatar
Gemy:24.5.2020 17:07

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

Odpovědět
24.5.2020 17:07
Člověk je tvor logický, a proto jedná v afektu.
Avatar
Gemy
Člen
Avatar
Odpovídá na Gemy
Gemy:24.5.2020 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);
Odpovědět
24.5.2020 18:15
Člověk je tvor logický, a proto jedná v afektu.
Avatar
x.listo
Člen
Avatar
x.listo:26.6.2021 20:43

Na vysvětlenou tohoto řádku

String.format("%1$-" + (celkem + 1) + "s", s)

Dobře jsem to pochopil podle tohoto tutoriálu na javatpoint.com

V podstatě se jedná od rozšíření %s. Vložením 1$ za znak procento. Vkládáme hodnotu z prvního parametru, tady je to proměnná s. Při použití jen jednoho parametru jej můžeme vynechat. Symbol pomlčka určuje, že se mezery doplní na pravou stranu. Potom následuje číslo, které udává celkový počet znaků. Zde je doplněno z proměnné "celkem+1".

Na jednoduchou ukázku

String s1 = "DlouheSlovo";
String s2 = "DruheSlovo ";

//doplní mezery na pravou stranu, do celkové délky 40 znaků
System.out.printf("|%-40s|\n",s1);
//doplní mezery na levou stranu, do celkové délky 40 znaků
System.out.printf("|%40s|\n",s1); znaků
//dosadí text z druhého a pak z prvního parametru, ke každému doplní 20 znaků
System.out.printf("|%2$20s%1$20s|\n",s1,s2);
//dosadí text z prvního a pak z druhého parametru, ke každému doplní 20 znaků
System.out.printf("|%1$20s%2$20s|\n",s1,s2);
//stejné jako předchozí, jen u prvního parametru doplní mezery na pravou stranu
System.out.printf("|%1$-20s%2$20s|\n",s1,s2);

Výsledek`

|DlouheSlovo                             |
|                             DlouheSlovo|
|         DruheSlovo          DlouheSlovo|
|         DlouheSlovo         DruheSlovo |
|DlouheSlovo                  DruheSlovo |
 
Odpovědět
26.6.2021 20:43
Avatar
Honza
Člen
Avatar
Honza:7.8.2021 10:53

Ahoj, chtěl bych se zeptat, co se stane s atributama, které jsou jen v potomkovy a předkovy ne:

Bojovnik gandalf = new Mag("Gandalf", 60, 15, 12, kostka, 30, 45);

např. když bych nastavil atributy mága na public a vypsal je v jiné třídě

System.out.println(gandalf.mana);

(vím, že se to nemá, ale nevím, jak bych se jinak zeptal :-D ), tak to nepůjde, ale když bych to chtěl vypsat ve třídě Mág.java tak to jde, to mám jako chápat, že ta reference v tomto případě odkazuje pouze na atributy společné ? a ve třídě Mág ? To jsou ty data uložený v atributech té instance, ale nelze k nim přistupovat přes referenci (typu Bojovnik), ale pouze přes třídu ve které byly deklarovány? Děkuji :-)

 
Odpovědět
7.8.2021 10:53
Avatar
Atrament
Super redaktor
Avatar
Odpovídá na Honza
Atrament:7.8.2021 12:17

Předek neví nic o extra atributech a metodách potomka, takže pokud gandalf je definovaný jako Bojovnik tak bude jenom 'vědět' o metodách a atributech Bojovnika. Jelikož jsi ale udělal new Mag a Mag je potomek Bojovnika, tak ty informace tam jsou a můžeš se k nim dostat tak, že gandalfa přetypuješ na Maga, to je vysvětleno dále v kurzu...

System.out.println(((Mag) gandalf).mana);
 
Odpovědět
7.8.2021 12:17
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Robert Vyskup:21.8.2021 21:34

Jen taková technická, přece nemusíme měnit

public String graficky ukazatel

na protected. Když je public tak k němu má přece potomek přístup stejně jako další třídy kde má Bojovnik instanci. Chápu, že chceme pak tu novou metodu chránit tak ji dáme protected. Ale klidně to přece mohlo zůstat public. V textu je to napsané tak, jako bychom tu metodu v potomkovi nemohli použít pokud nebude protected.

 
Odpovědět
21.8.2021 21:34
Avatar
Karel Potácel:12.10.2021 18:38

S tímto příkladem mám problém. nemohu v netbeans zprovoznit dědičnost. nevím proč mě to háže chybu.

 
Odpovědět
12.10.2021 18:38
Avatar
Atrament
Super redaktor
Avatar
Odpovídá na Karel Potácel
Atrament:12.10.2021 19:08

Když klikneš na tu žárovičku s červenou tečkou tak ono ti to nabídne řešení, případně aspoň řekne co se tomu nelíbí...

 
Odpovědět
12.10.2021 19:08
Avatar
Odpovídá na Atrament
Karel Potácel:12.10.2021 20:01

Dík. Kouknu na to. Stáhl jsem si tahový boj z ITnetwork a ten funguje. To je dobrá zpráva. Chyba je jen, v mém kodu. Na to příjdu.

 
Odpovědět
12.10.2021 20:01
Avatar
SARNOVSKÝ Petr:5.12.2021 15:41

Ahoj,
ještě nezměnil ;-)

Abychom nemuseli logiku se složením ukazatele psát dvakrát, upravíme metodu grafickyZivot() v Bojovnik.java. Připomeňme si, jak vypadá:

...ale je nakonec k pochopení, že je to zjednodušení for cyklu.

 
Odpovědět
5.12.2021 15:41
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 72. Zobrazit vše