3. diel - Hracia kocka v Jave - Zapuzdrenie, konštruktor a Random
V predchádzajúcom cvičení, Riešené úlohy k 2. lekcii OOP v Jave, sme si precvičili získané skúsenosti z predchádzajúcich lekcií.
V dnešnom tutoriáli začneme pracovať na sľúbenej aréne, v ktorej budú proti sebe bojovať dvaja bojovníci. Boj bude ťahový (na preskáčku) a bojovník vždy druhému uberie život na základe sily jeho útoku a obrany druhého bojovníka. Simulujeme v podstate stolnú hru, budeme teda simulovať aj hraciu kocku, ktorá dodá hre prvok náhodnosti. Začnime zvoľna a vytvorme si dnes práve túto hraciu kocku. Zároveň sa naučíme ako definovať vlastný konštruktor.
Vytvorenie projektu
Vytvorme si nový projekt a pomenujme ho TahovyBoj
. K projektu
si pridajme novú triedu s názvom Kostka
. Zamyslime sa nad
atribútmi, ktoré kocke dáme. Iste by sa hodilo, keby sme si mohli zvoliť
počet stien kocky (klasicky 6 alebo 10 stien, ako je zvykom pri tomto type
hier). Ďalej bude kocka potrebovať tzv. generátor náhodných čísel. Ten
nám samozrejme poskytne Java, ktorá na tieto účely obsahuje triedu
Random
. Aby sme ju mohli používať, musíme si triedu
java.util.Random
naimportovať. Import napíšeme hore, ako sme
zvyknutí z používania importu pre Scanner
. Naša trieda bude
mať teraz 2 atribúty:
pocetSten
typuint
arandom
typuRandom
, kde bude náhodný generátor.
Minule sme kvôli jednoduchosti nastavovali všetky atribúty našej triedy
ako public
, teda ako verejne prístupné. Väčšinou sa však
skôr nechce, aby sa dali zvonku modifikovať a používa sa modifikátor
private
. Atribút je potom viditeľný len vo vnútri triedy a
zvonku sa Java tvári, že vôbec neexistuje. Pri návrhu triedy teda nastavíme
všetko na private
av prípade, že niečo bude naozaj potrebné
vystaviť, použijeme modifikátor public
. Naša trieda teraz
vyzerá takto:
Riadok:
nám hovorí: nastav ako
privátny (neverejný) atribút random
dátového typu
Random
. Uložíme tak do atribútu celú triedu Random
a môžeme v triede v akejkoľvek metóde volať napríklad metódu
random.nextInt()
, bez toho aby sme tam znovu zakladali
premennú.
Konštruktory
Až doteraz sme nevedeli zvonku nastaviť iné atribúty ako
public
, pretože napr. private
nie sú zvonku
viditeľné. Už sme si hovorili niečo málo o konštruktore objektu. Je to
metóda, ktorá sa zavolá vo chvíli vytvorenia inštancie
objektu. Slúži samozrejme na nastavenie vnútorného stavu objektu a
na vykonanie prípadnej inicializácie. Inštanciu kocky by sme teraz v súbore
TahovyBoj.java
vytvorili takto:
Práve slovo
Kostka()
je konštruktor. Pretože v našej triede
Kostka
žiadny konštruktor nie je, Java si dogeneruje prázdnu
metódu. My si však teraz konštruktor do triedy pridáme. Deklaruje sa ako
metóda, ale nemá návratový typ a musí mať
rovnaký názov ako je názov triedy (začína teda, na rozdiel
od ostatných metód, veľkým písmenom), v našom prípade teda
Kostka
. V konštruktore nastavíme počet stien na pevnú hodnotu a
vytvoríme inštanciu triedy Random
. Konštruktor bude vyzerať
nasledovne:
Ak kocku teraz vytvoríme,
bude mať atribút pocetSten
hodnotu 6
av atribúte
random
bude vytvorená inštancia generátora náhodných čísel.
Vypíšme si počet stien do konzoly, nech vidíme, že tam hodnota naozaj je.
Nie je dobré atribút nastaviť na public
, pretože nebudeme
chcieť, aby nám niekto mohol už pri vytvorenej kocke meniť počet stien.
Pridáme do triedy teda metódu vratPocetSten()
, ktorá nám vráti
hodnotu atribútu pocetSten
. Docielili sme tým v podstate to, že
je atribút read-only (atribút nie je viditeľný a možno ho iba
čítať metódou, zmeniť ho nemožno). Nová metóda bude vyzerať asi
takto:
Presuňme sa do súboru
TahovyBoj.java
a vyskúšajme si vytvoriť kocku a vypísať počet
stien:
Výstup:
Vidíme, že sa konštruktor
naozaj zavolal. My by sme ale chceli, aby sme mohli pri každej kocke pri
vytvorení špecifikovať, koľko stien budeme potrebovať. Prejdeme do triedy
Kostka.java
a dáme teda konštruktoru parameter:
Všimnite si, že sme pred
názov parametra metódy pridali znak a
, pretože inak by mal
rovnaký názov ako atribút a Javu by to zmiatlo. Vráťme sa do súboru
TahovyBoj.java
a zadajte tento parameter do konstruktoru:
Výstup:
Všetko funguje, ako sme
očakávali. Java nám už v tejto chvíli nevygeneruje prázdny (tzv.
bezparametrický konštruktor), takže kocku bez parametra vytvoriť nemožno.
My to však môžeme umožniť, vytvorme si ďalší konštruktor a tentoraz bez
parametra. V ňom nastavíme počet stien na 6, pretože takú hodnotu asi
užívateľ našej triedy pri kocke očakáva ako východiskový. Prejdeme teda
späť do súboru Kostka.java
a vytvoríme konštruktor bez
parametra:
Trieda Kostka
má teda teraz dvoch konštruktorov.
Skúsme si teraz vytvoriť 2 inštancie kocky, každú iným konštruktorom v
súbore TahovyBoj.java
:
Výstup:
Jave nevadí, že máme dve
metódy s rovnakým názvom, pretože ich parametre sú rôzne. Hovoríme o tom,
že metóda Kostka()
(teda tu konštruktor) má
preťaženie (overload). To môžeme využívať aj pri
všetkých ďalších metódach, nielen pri konštruktoroch. IDE nám prehľadne
ponúka všetky preťaženia metódy vo chvíli, keď zadáme jej názov. V
ponuke vidíme naše 2 konštruktory:
- .<>
- .<>
indexOf()
na triede String. Je dobré si pri metódach
prejsť ich preťaženie, aby ste neprogramovali niečo, čo už niekto urobil
pred vami.
Ukážeme si ešte, ako ide obísť nepraktický názov atribútu u
parametrického konštruktora (v našom prípade aPocetSten
) a
potom konštruktory opustíme. Problém je samozrejme v tom, že keď
napíšeme:
Java nevie, ktorú z
premenných myslíme, či parameter alebo atribút. V tomto prípade
priraďujeme do parametra znovu ten istý parameter. IDE nás na túto
skutočnosť dokonca upozorní. Vnútri triedy sa máme možnosť odkazovať na
jej inštanciu, je uložená v premennej this
. Využitie si
môžeme predstaviť napr. keby kocka mala metódu
dejHraci(Hrac hrac)
a tam by volala
hrac.seberKostku(this)
. Tu by sme hráči pomocou referenčnej
premennej this
odovzdali seba samého, teda tú konkrétnu kocku, s
ktorou pracujeme. My sa tým tu nebudeme zaťažovať, ale využijeme odkaz na
inštanciu pri nastavovaní atribútu:
Pomocou premennej
this
sme špecifikovali, že ľavá premenná
pocetSten
patrí inštancii, pravú Java chápe ako z parametra.
Máme teda dva konštruktory, ktoré nám umožňujú tvoriť rôzne hracie
kocky. Prejdime ďalej.
Náhodné čísla
Definujme na kocke metódu hod()
, ktorá nám vráti náhodné
číslo od 1
do počtu stien. Je to veľmi jednoduché, metóda
bude public
(pôjde volať zvonku triedy) a nebude mať žiadny
parameter. Návratová hodnota bude typu int
. Náhodné číslo
získame tak, že na generátore random
zavoláme metódu
nextInt()
. Tá má dve preťaženia:
nextInt()
- Variant bez parametra vracia náhodné číslo v celom rozsahu dátového typuint
, pre úplnosť teda konkrétne od-2147483648
do2147483647
.nextInt(do)
- Vracajú nezáporné čísla menšie ako medzado
. Napríkladrandom.nextInt(100)
teda vráti číslo od0
do99
.
Kostka.java
teda:
Dajte si pozor, aby ste
netvorili generátor náhodných čísel v metóde, ktorá má náhodné číslo
vracať, teda že by sa pre každé náhodné číslo vytvoril nový generátor.
Výsledné čísla potom nie sú takmer náhodné alebo dokonca vôbec. Vždy si
vytvorte jednu zdieľanú inštanciu generátora (napr. do privátneho atribútu
pomocou konštruktora) a na tej potom metódu nextInt()
volajte.
Prekrývanie metódy
toString()
Kocka je takmer hotová, ukážme si ešte jednu užitočnú metódu, ktorú
ju pridáme a ktorú budeme hojne používať aj vo väčšine našich
ďalších objektov. Reč je o metóde toString()
, o ktorej sme sa
už zmienili a ktorú obsahuje každý objekt, teda aj teraz
naša kocka. Metóda je určená na to, aby vrátila tzv. textovú
reprezentáciu inštancie. Hodí sa vo všetkých prípadoch, keď si
inštanciu potrebujeme vypísať alebo s ňou pracovať ako s textom. Túto
metódu majú napr. aj čísla. Už vieme, že v Jave funguje implicitná
konverzia, akonáhle teda budeme chcieť do konzoly vypísať objekt, Java na
ňom zavolá metódu toString()
a vypíše jej výstup. Ak si
robíme vlastnú triedu, mali by sme zvážiť, či sa nám takáto metóda
nehodí. Nikdy by sme si nemali robiť vlastnú metódu, napr.
niečo ako vypis()
(čo sme používali doteraz), keď máme v Jave
pripravenú cestu, ako toto riešiť. U kocky nemá metóda
toString()
vyšší zmysel, ale u bojovníka bude určite vracať
jeho meno. My si ju ku kocke aj tak pridáme, bude vypisovať, že sa jedná o
kocku a vráti aj počet stien. Najprv si skúsme vypísať do konzoly našu
inštanciu kocky:
Do konzoly sa vypíše iba cesta k našej triede, teda
cz.itnetwork.Kostka
a tzv. hash kód objektu. V mojom prípade bol
vypísaný tento reťazec:
Metódu
toString()
už jednoducho nedefinujeme, ale pretože už existuje,
musíme ju prepísať, resp. prekryť. Tým sa opäť nebudeme
teraz podrobne zaoberať, ale chcem, aby sme už teraz vedeli metódu
toString()
používať. Pre prehľadné prekrytie označíme
metódu anotácií @Override
:
Teraz opäť skúsime do konzoly vypísať priamo inštanciu kocky.
Výstup:
Ešte si naše kocky vyskúšame. Skúsime si v programe s našimi dvoma kockami v cykloch hádzať a pozrieme sa, či fungujú tak, ako sa očakáva:
Výstup môže vyzerať nejako takto:
Máme hotovú celkom peknú a nastaviteľnú triedu, ktorá reprezentuje hraciu kocku. Bude sa nám hodiť v našej aréne, ale môžete ju použiť aj kdekoľvek inde. Vidíme, ako OOP umožňuje znovupoužívať komponenty.
V nasledujúcom cvičení, Riešené úlohy k 3. lekcii OOP v Jave, si precvičíme nadobudnuté skúsenosti z predchádzajúcich lekcií.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 2255x (9.37 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Java