2.1. Vytvoření vlastní třídy
Strana 1 z 41
2. Vytváříme vlastní třídu Obsah 2.1 Vytvoření vlastní třídy ........................................................................................................... 2 2.2 Zdrojový kód třídy.................................................................................................................. 3 Základní vlastnosti zabudovaného editoru ................................................................................................... 5 Soubor se zdrojovým kódem.......................................................................................................................... 6 Tři druhy komentářů........................................................................................................................................ 6
2.3 Definice třídy .......................................................................................................................... 7 2.4 Úprava konstruktoru.............................................................................................................. 9 2.5 Konstruktor s parametry ..................................................................................................... 12 Konstruktor this............................................................................................................................................. 12
2.6 Syntaktické definice ............................................................................................................ 13 2.7 Dokumentační komentáře ................................................................................................... 15 Pomocné značky............................................................................................................................................ 16
2.8 Definice atributů................................................................................................................... 17 Možné důsledky zveřejnění atributů ............................................................................................................ 19
2.9 Definujeme vlastní metodu ................................................................................................. 20 2.10 Kvalifikace a klíčové slovo this ........................................................................................ 22 2.11 Metody vracející hodnotu.................................................................................................. 23 Použití metod vracejících hodnotu .............................................................................................................. 23
2.12 Zapouzdření........................................................................................................................ 24 2.13 Lokální proměnné .............................................................................................................. 25 2.14 Atributy třídy (statické atributy)........................................................................................ 26 2.15 Metody třídy (statické metody) ......................................................................................... 27 Kvalifikace atributů a metod třídy ................................................................................................................ 28
2.16 Konstanty a literály............................................................................................................ 30 2.17 Předání parametru objektového typu............................................................................... 31 2.18 Dokumentace ..................................................................................................................... 33 2.19 Shrnutí – co jsme se v kapitole naučili ............................................................................ 38
V minulé kapitole jsme spíše teoretizovali a ukazovali si, jak co funguje. V této kapitole začneme opravdu programovat a napíšeme své první řádky. Nezačneme však od nuly, ale budeme rozšiřovat projekt, s nímž jsme se seznámili v minulé kapitole. Předem se omlouvám, že tato kapitola bude asi trochu delší, protože se v ní budeme postupně seznamovat se zápisem všech konstrukcí, které jsme si v minulé kapitole vysvětlili. Budeme se v ní proto věnovat prakticky pouze kódu, tj. tomu, jak to či ono zapsat. Od příští kapitoly bych chtěl již obě části výkladu vyvážit. Vždy si budeme chvíli vyprávět o třídách, objektech a jejich vlastnostech, a pak si ukážeme, jak to, co jsme se právě naučili, zapsat do programu. Pro práci s touto kapitolou si z adresy http://vyuka.pecinovsky.cz/ stáhněte projekt 02_Tvary a soubor rozbalte do své složky s projekty. Rozbalte jej přitom i s podsložkami, takže vznikne složJ02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 1 z 41
2.1. Vytvoření vlastní třídy
Strana 2 z 41
ka 02_tvary-0, v níž bude vedle tříd, s nimiž jsme se setkali v minulé kapitole, také třída Smrk, o které budu hovořit v kapitole této.
2.1 Vytvoření vlastní třídy Říkali jsme si, že základem všeho jsou objekty a ty že jsou instancemi svých tříd. Abychom mohli mít objekt, musíme mít nejprve třídu, jejíž instancí objekt bude. Poté jsme se dozvěděli, že objekty vytvoříme tak, že prostřednictvím operátoru new zavoláme konstruktor, což je speciální metoda mateřské třídy vytvářených objektů. Tato metoda nemá na starosti prakticky nic jiného, než objekt správně vytvořit. Zůstaneme ještě chvíli v minulém projektu a podíváme se, jak bychom mohli vytvořit novou třídu a jak bychom v ní nadefinovali konstruktor, jenž by vytvořil ten správný objekt. 1.
Stiskneme vlevo tlačítko Nová třída.
Obrázek 2.1: Vytvoření nové třídy. 2.
V následně otevřeném dialogovém okně zadejte název třídy, který musí odpovídat pravidlům pro identifikátory (zadejte např.Smrk).
Obrázek 2.2: Zadání názvu vytvářené třídy.
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 2 z 41
2.2. Zdrojový kód třídy 3.
Strana 3 z 41
Ověřte, že budete opravdu vytvářet obyčejnou třídu a své zadání potvrďte. BlueJ pak přidá právě vytvořenou třídu do diagramu tříd.
Obrázek 2.3: Přidání nové třídy do diagramu tříd.
Obdélník s novou třídou je prozatím vyšrafován, ale my již víme, že šrafování znamená jen to, že třída ještě není přeložena. Stiskneme proto tlačítko Přeložit a můžeme hned zkusit vytvořit instanci nově definované třídy. Konvence při tvorbě identifikátorů: V programech psaných v jazyku Java se ustálily jisté konvence. Jednou z nich je zvyk definovat všechny identifikátory tříd s velkým počátečním písmenem a identifikátory instancí a metod s malým počátečním písmenem. Sestává-li identifikátor z několika slov, používá se tzv. velbloudí notace, při níž je každé počáteční písmeno dalšího slova v identifikátoru velké a ostatní písmena jsou malá – např. DlouhýNázevTřídy nebo dlouhýNázevMetody().
2.2 Zdrojový kód třídy Instance se vytvoří, ale nebude nic umět. V místní nabídce je sice položka String toString(), ale tato metoda slouží spíše pro následné ladění – jejím jediným úkolem je vrátit textový řetězec obsahující dostatečné informace pro identifikaci instance. Vybavení třídy potřebnými schopnostmi je na nás. Abychom tak mohli učinit, musíme otevřít její zdrojový kód, tj. soubor, kam jsme my nebo někdo jiný zapsali program. Můžeme toho dosáhnout dvěma způsoby: J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 3 z 41
2.2. Zdrojový kód třídy
Strana 4 z 41
poklepeme na třídu (přesněji na její ikonu, tj. na příslušný obdélník v diagramu tříd), v místní nabídce třídy zadáme příkaz Otevřít v editoru. Vyberte si postup, který je vám sympatičtější a otevřete editor se zdrojovým kódem třídy, který pro nás vygeneroval BlueJ v okamžiku, kdy jsme jej požádali o vytvoření nové třídy. Je to téměř prázdná definice třídy, do které budeme vpisovat náš program. Jinými slovy: BlueJ za nás napsal to, co bychom stejně museli (nebo alespoň měli) napsat a přidal i nějaké komentáře, které mají pomoci výsledný program zpřehlednit a uspořádat.
Obrázek 2.4: Okno zabudovaného editoru Poznámka: Všechny současné programátorské editory používají barevné zvýraznění syntaxe, které výrazným způsobem zvyšuje přehlednost a srozumitelnost programu. Protože webová podoba tohoto učebního textu umožňuje využití barev, budu se snažit použít toto barevné zvýraznění i v ukázkách programů uvedených v textu.
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 4 z 41
2.2. Zdrojový kód třídy
Strana 5 z 41
Základní vlastnosti zabudovaného editoru Autoři editoru dodávaného s prostředím BlueJ se snažili vytvořit program maximálně jednoduchý, aby žáci zvládli jeho ovládání co nejrychleji, avšak na druhou stranu dostatečně komfortní, aby jim tvorbu jejich programů co nejvíce usnadnil. Mezi základní „komfortní doplňky“, které v současné době patří již k téměř povinné výbavě všech programátorských editorů, patří možnost automatického odsazování, barevného zvýraznění syntaxe, vytváření záložních kopií, zobrazování čísel řádků a schopnost dohledání a označení párové závorky k závorce, u které je textový kurzor. Navíc nám zabudovaný editor umožňuje nastavit velikost použitého písma (jinou použijeme při vlastní tvorbě a jinou pak při její prezentaci před skupinou posluchačů). Všechny tyto vlastnosti můžeme nastavit či naopak potlačit v dialogovém okně, jež vyvoláme příkazem Předvolby → Nastavení….
Obrázek 2.5: Nastavení předvoleb pro editor a překladač.
Když už jsme toto dialogové okno otevřeli, povíme si i o ostatních možnostech, které jdou na kartě Různé nastavit. Prvním z nich je povolení novinek z JDK 1.4. Verze 1.4 totiž zavedla nové klíčové slovo assert. Jeho použití je však implicitně zakázáno pro případ, že by je někdo ve svých starších programech již použil jako identifikátor. Kdo však ví, že slovo assert ve svých programech nikdy nepoužil, může je povolit. Protože my vytváříme programy zcela nové, rádi jeho použití povolíme, abychom později mohli využít jeho příjemných vlastností. Druhou možností je nastavení adresy s dokumentací standardní knihovny. Po instalaci je zde nastavena internetová adresa této dokumentace na stránkách firmy Sun. Pokud jste spolu s JDK instalovali i jeho dokumentaci, doporučuji vám přepsat tuto adresu na lokální adresu ve vašem počítaJ02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 5 z 41
2.2. Zdrojový kód třídy
Strana 6 z 41
či. Na obrázku 2.5 si všimněte, že se zde nastavuje absolutní cesta k souboru index.html ve složce api, jež je podložkou složky, do níž jste dokumentaci instalovali. Pokud jste se zalekli rozměru dokumentace a neinstalovali jste ji, zrušte zaškrtnutí políčka Použít toto URL při generování projektové dokumentace. Jedinou výhodou, o níž se zrušením tohoto zaškrtnutí připravíte, je to, že do vaši dokumentace nebudou vloženy odkazy na dokumentaci souvisejících částí standardní knihovny. Až si budeme povídat o dokumentaci, ještě se k tomu vrátím.
Soubor se zdrojovým kódem Vraťme se ale k editoru, jehož okno je na obrázku 2.4 a podívejme se na kód právě vytvořené třídy Smrk. Prozradím vám, že tento kód je uložen v souboru, který se jmenuje stejně jako v něm definovaná třída a který má příponu .java. To je důležité! Kdybyste totiž později chtěli přejmenovat třídu, musíte myslet na to, že spolu se třídou se musí přejmenovat i soubor, v němž je její zdrojový kód. (Navíc se musí přejmenovat všechny konstruktory, které se také jmenují stejně jako třída.) Poznámka: V souboru s příponou .java je opravdu vše, co potřebujete. Budete-li chtít někdy své programy někam přenést, stačí přenést pouze soubory .java. Vše ostatní potřebné pro správný vývoj programu si již BlueJ (a většina ostatních vývojových prostředí) dokáže znovu vytvořit .
Tři druhy komentářů Na počátku vygenerovaného zdrojového kódu najdeme komentář. Jeho podoba odpovídá podobě komentáře, který znáte z Baltíkových programů: obecný komentář začíná dvojicí znaků /* a končí inverzní dvojicí */ – tyto dvojice slouží jako komentářové závorky. Vše, co mezi nimi překladač najde, ignoruje. Zapamatujte si, že komentář má stejný význam jako mezera (jinými slovy: kde smí být mezera, tam smí být komentář – výjimkou je pouze vnitřek textových řetězců). Vedle výše popsaných obecných komentářů, jejichž délka není nijak omezena, existují ještě jednořádkové komentáře (ty také znáte z Baltíka), které začínají dvojicí znaků // a končí spolu s koncem řádku. Programovací jazyk Java zavádí navíc ještě dokumentační komentář, který vypadá skoro stejně jako obecný komentář a liší se pouze tím, že začíná trojicí znaků /**. Do těchto komentářů se zapisuje dokumentace k vytvářenému programu. Časem se k nim ještě vrátíme. Pokračovací řádky obecných a dokumentačních komentářů bývá dobrým zvykem začínat hvězdičkami. Ty sice nejsou povinné, ale zvyšují přehlednost programu. Proto je tam řada programátorských editorů (mezi nimi i BlueJ) automaticky vkládá. Zkuste klepnout do kteréhokoliv řádku uprostřed dokumentačního komentáře a stisknout Enter – editor vloží nový řádek a zahájí jej tím, že pod hvězdičku současného řádku vloží také hvězdičku a znakový kurzor přesune až za ni. Kdybyste do programu někam vložili obecný komentář, zjistite, že se chová stejně. Vhodné komentáře dokáží výrazně zvýšit čitelnost programu. Naučte se své programy dostatečně komentovat, abyste pak při pozdějších úpravách nemuseli pracně analyzovat, jak jste to tenkrát mysleli. V průběhu seriálu se k této problematice vrátím ještě podrobněji. J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 6 z 41
2.3. Definice třídy
Strana 7 z 41
Úkol: Doplňte dokumentační komentář na začátku souboru o popis účelu dané třídy, název autora a popis verze. Můj soubor by pak začínal následovně: /** * Trida Smrk slouzi k vyuce zakladu prace se zdrojovym kodem. * Je soucasti projektu Tvary, jenz je startovacim projektem * kurzu objektove orientovaneho programovani. * * @author Rudolf Pecinovsky * @version 1.06, 2.1.2003 */
2.3 Definice třídy Projdeme si nyní vlastní definici třídy, ukážeme si, z jakých se skládá částí a povíme si, co jednotlivé části znamenají: public klíčové slovo, které říká, že třída je veřejná a kdokoliv (tedy i BlueJ) ji může použít. class
klíčové slovo oznamující, že definujeme novou třídu.
Smrk
název definované třídy. Musí vyhovovat pravidlům pro tvorbu identifikátorů (viz sekce Pravidla pro tvorbu identifikátorů v kapitole 1. Třídy a objekty) a podle konvence by měl začínat velkým písmenem.
{…}
vše, co je uzavřeno v následujících složených závorkách, označujeme jako tělo třídy. Vše, co je před tělem třídy, označujeme jako hlavička třídy.
//Smrk nepovinný závěrečný komentář, který sem ve svých programech vkládám proto, abych rychle poznal, kterou třídu jsem právě definoval, a to i tehdy, uvidím-li pouze její konec. Komentář mi navíc pomáhá určit, že právě tato uzavírací závorka je koncem těla třídy. S výjimkou dvou přesně specifikovaných příkazů (budeme o nich mluvit později) musí být v jazyku Java vše ostatní, tj. atributy i metody, definováno v těle třídy. Definice třídy ve vygenerovaném programu začíná sérií komentářů, které nám napovídají pořadí, v němž je vhodné do programu zařazovat definice jednotlivých částí třídy. Toto pořadí sice není povinné, ale pokud si na ně zvyknete a budete je dodržovat, budete se ve svých programech mnohem rychleji orientovat. Abyste si ověřili, že to opravdu stačí, požádejte BlueJ o vytvoření nové třídy, kterou nazvete např. PrázdnáTřída (klidně si na ní vyzkoušejte, že Java diakritiku zvládá). Pak otevřete její zdrojový kód a vše, co nemusí být v definici, smažte. Výsledkem bude definice: public class PrázdnáTřída { }
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 7 z 41
2.3. Definice třídy
Strana 8 z 41
Abyste si vyzkoušeli, že Javě je úplně jedno, kde končí řádky, upravte definici do toho nejstručnějšího tvaru: public class PrázdnáTřída{}
Abychom mohli náš kód vyzkoušet, musíme jej nejprve přeložit. Stiskněte proto na horní liště editoru tlačítko Přeložit. Jak nám BlueJ oznámí v dolním informačním okně, tak nejprve upravený soubor uloží, pak se na chvíli zamyslí a za chvíli nám v tomto poli oznámí, že „Třída byla úspěšně přeložena – žádné syntaktické chyby“.
Obrázek 2.6: Okno editoru se zprávou o úspěšném překladu třídy PrázdnáTřída.
Překladem třídy zmizí i šrafování ikony třídy v diagramu tříd. Můžeme tedy zkusit vytvořit její instanci. Možná vás překvapí, že v místní nabídce třídy najdete její konstruktor, i když jste žádný nedefinovali. Je to proto, že třída nějaký konstruktor mít musí. Autoři jazyka nás ale nechtěli nutit psát prázdné, nic nedělající konstruktory. Definovali proto jazyk tak, že v případě, kdy vůbec žádný konstruktor nenadefinujeme, tak se nás překladači zželí a místo toho, aby nás nutil něco doplňovat, nadefinuje prázdný bezparametrický konstruktor místo nás sám. Zkuste tedy vytvořit instanci a ověřte, že vše funguje.
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 8 z 41
2.4. Úprava konstruktoru
Strana 9 z 41
Obrázek 2.7: Instance a místní nabídka prázdné třídy
Samozřejmě, že s takto vytvořenou instancí nemůžeme skoro nic dělat. Otevřete proto její místní nabídku, nechte ji odstranit a totéž pak proveďte i s celou třídou. Protože odstranění třídy je přece jenom operace, která má na celý projekt zásadnější dopad, tak se vás BlueJ pro jistotu nejprve zeptá, jestli to s tím odstraněním třídy myslíte vážně. Jakmile svůj úmysl potvrdíte, odstraní nejenom zdrojový soubor třídy, ale i všechny zmínky o tom, že třída byla někdy součástí projektu.
Obrázek 2.8: Potvrzovací dotaz před smazáním třídy
2.4 Úprava konstruktoru Vraťme se zpět k naší třídě Smrk. Jak naznačují komentáře, první skutečnou definicí v automaticky vygenerovaném zdrojovém textu třídy Smrk je definice konstruktoru. Všimněte si, že tato definice opět začíná klíčovým slovem public oznamujícím, že konstruktor je veřejně přístupný.
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 9 z 41
2.4. Úprava konstruktoru
Strana 10 z 41
Konstruktor poznáme podle toho, že se jmenuje stejně jako třída, jejíž instanci vytváří. Za názvem by měl následovat seznam parametrů, ale protože tento konstruktor žádné parametry nemá, budou závorky prázdné. Modifikátory (v našem případě klíčové slovo public), název třídy a seznam parametrů v závorkách tvoří hlavičku konstruktoru. V hlavičce je uvedeno vše, co ostatní třídy o daném konstruktoru vědí. Co není uvedeno v hlavičce, to okolní svět o konstruktoru neví. Za hlavičkou je ve složených závorkách tělo konstruktoru. Je složeno z posloupnosti příkazů popisujících, co bude konstruktor dělat. Každý příkaz musí být ukončen středníkem. Přitom je zcela jedno, vejde-li se celý příkaz na jeden řádek, nebo bude-li rozprostřen na několika řádcích. Jak jsem již řekl, zvykl jsem si pro zvýšení přehlednosti svých programů vkládat za uzavírací závorky těl tříd a metod komentář, který znovu obsahuje hlavičku. Záleží na vás, jestli tento zvyk převezmete nebo ne. Pokusme se nyní definovat tělo konstruktoru tak, aby nám konstruktor nakreslil malý smrček. Pamatujete-li si, jak vypadaly parametrické konstruktory v místních nabídkách tříd, asi jistě odvodíte, že by definice konstruktoru mohla vypadat např. následovně: public Smrk() { new Trojuhelnik( 10, 0, 30, 30 ); new Trojuhelnik( 5, 10, 40, 40 ); new Trojuhelnik( 0, 20, 50, 50 ); }//public Smrk() Poznámka k formátu: Všimněte si, že příkazy uvnitř těla konstruktoru jsou oproti hlavičce odsazeny. Obdobně jsou odsazeny všechny definice uvnitř těla třídy. Obecně se dodržuje zásada, že všechny příkazy uvnitř bloku příkazů ve složených závorkách se oproti okolním příkazům odsazují o zadaný počet mezer (BlueJ má předdefinované 4 mezery, ale lze to změnit – většinou se používají 2 až 4 mezery). O stejný počet mezer se pak odsazují i pokračovací řádky příkazů, které se „nevejdou“ na jeden řádek (přesněji které rozdělíte do několika řádků). Dosažení takovéhoto vzhledu není naštěstí pracné. Stačí před zadáním prvního odsazeného řádku stisknout tabulátor a další řádky se již automaticky odsadí podle toho prvního. Zároveň si všimněte, že otevírací a zavírací složená závorka jsou pod sebou na úrovni hlavičky. Pro ty, kteří si zvykli na odsazování, které se používá v Baltíkovi, to bude změna. Baltík totiž zavedl jiné odsazování, než na jaké je zvyklý zbytek světa. Protože na toto odsazování je v Baltíkovi vázán zrychlený výběr bloků, použil jsem je i ve své učebnici. Teď vás budu naopak nabádat, abyste přešli na uspořádání, které je v programátorském světě mnohem běžnější. Programátoři se odlišují v tom, zda dávají otevírací závorku na samostatný řádek či na konec předchozího řádku. V umístění zavírací závorky se však většinou shodnou. Výhodou otevírací závorky na konci řádku jsou kratší programy, výhodou závorky na samostatném řádku je snazší kontrola párování závorek. Protože druhý důvod považuji pro začátečníky za důležitější, budu v tomto kurzu umísťovat otevírací a zavírací složené závorky na samostatné řádky.
Abychom mohli náš kód vyzkoušet, musíme jej opět přeložit. Jak vypadá úspěšný překlad jsme již viděli. Podívejme se nyní na to, jak se bude BlueJ chovat v případě, kdy budeme mít ve zdrojovém textu nějakou chybu.
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 10 z 41
2.4. Úprava konstruktoru
Strana 11 z 41
Odstraňte středník ze závěrečného příkazu v těle konstruktoru a spusťte překlad. BlueJ váš program opět nejprve uloží a pak jej začne překládat. Když narazí na chybu, zobrazí v dolním informačním poli chybovou zprávu. Tato zpráva sice bude anglicky, ale klepnutím na otazník na pravém okraji informačního pole otevřete dialogové okno, které vám chybové hlášení přeloží a možná i česky vysvětlí – viz obr.2.9.
Obrázek 2.9: Vysvětlení nalezené chyby s návodem k nápravě
Tato vysvětlení sice nejsou k dispozici pro všechny chyby, nicméně nejčastější chyby takto vysvětleny jsou. Zkuste se nyní vrátit do prostředí BlueJ, vytvořte instanci třídy Smrk a přesvědčete se, že se na plátno požadovaný smrček opravdu nakreslil. Úkol 1: Přepněte se do projektu, jenž jste stáhli na počátku této kapitoly a definujte třídu Smrk2, v níž si budete zkoušet vlastní verze definic, které pak budete moci porovnat s definicemi ve třídě Smrk.
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 11 z 41
2.5. Konstruktor s parametry
Strana 12 z 41
Úkol 2: Definujte třídy Snehulak, jejíž instance nakreslí na plátno blankytného sněhuláka, Domek, jejíž instance nakreslí domek s okénkem a dveřmi, a Panak, jejíž instance nakreslí postavičku sestavenou z obdélníků, trojúhelníků a elips.
2.5 Konstruktor s parametry Stromek jsme sice nakreslili, ale vytvoříme-li druhý, nebudeme jej moci od prvního odlišit, protože se budou překrývat. Vytvoříme proto konstruktor s parametry, které nám umožní specifikovat, kam se má stromek nakreslit. Vzpomeneme si, že parametry se píší do kulatých závorek za název konstruktoru a že před každým parametrem musí být nejprve uveden jeho typ. Je-li parametrů více, oddělují se čárkou. Konstruktor umožňující nakreslit stromek na zadané souřadnice by mohl vypadat následovně: public Smrk( int x, int y ) { new Trojuhelnik( x+10, y, 30, 30 ); new Trojuhelnik( x+5, y+10, 40, 40 ); new Trojuhelnik( x, y+20, 50, 50 ); }//public Smrk( int x, int y )
Přidejte do zdrojového textu výše uvedený kód a třídu přeložte. Vraťte se pak do prostředí BlueJ a vytvořte na různých místech plátna několik instanci třídy Smrk. Přesvědčete se, že se stromky nakreslily opravdu tak, jak byl vaším záměrem. Poznámka: Jakmile napíšete (nebo smažete) první písmeno ve zdrojovém kódu, počítač ihned odstraní ze zásobníku všechny odkazy na instance třídy, jejíž kód právě upravujete. Zároveň označí tuto třídu v diagramu tříd jako nepřeloženou, tj. opět ji vyšrafuje.
Úkol 1: Zkuste nyní definovat pro svoji třídu Smrk2 konstruktor, kterému budete moci zadat nejenom počáteční pozici kresleného smrčku, ale také jeho rozměr. Protože je to úloha těžší, budete si moci v příští podkapitole prohlédnout její řešení. Úkol 2: Definujte obdobné parametrické konstruktory i pro svoje třídy Snehulak, Domek a Panak.
Konstruktor this Třídy Obdelnik, Elipsa a Trojuhelnik, které jsme doposud používali, měly každá po třech konstruktorech, jež se vzájemně lišily počtem zadávaných parametrů. Protože všechny konstruktory mají velice podobnou funkci, budou i jejich definice velice podobné. Programátoři jsou ale lidé líní (proto se také dali na programování) a neradi píší něco dvakrát. Java naštěstí nabízí způsob, jak se opakovanému psaní těla konstruktoru vyhnout – je jím použití J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 12 z 41
2.6. Syntaktické definice
Strana 13 z 41
klíčového slova this následovaného seznamem parametrů. Takto použité klíčové slovo this zastupuje jiný konstruktor téže třídy – který to je, to si překladač odvodí z počtu a typu zadaných parametrů. POZOR! Takovéto volání jiného konstruktoru musí být úplně prvním příkazem těla konstruktoru. Před ním smí být již pouze komentář.
Podívejme se, jak bychom mohli tuto možnost využít při definici našeho smrčku. Před chvilkou jste měli za úkol definovat konstruktor, kterému bychom zadali nejen počáteční pozici smrčku, ale také jeho velikost. Definice takovéhoto konstruktoru by mohla být např. následující: public Smrk( int x, int y, int sirka, int vyska ) { new Trojuhelnik( x+sirka/5, y, 3*sirka/5, 3*vyska/7 ); new Trojuhelnik( x+sirka/10, y+vyska/7, 4*sirka/5, 4*vyska/7 ); new Trojuhelnik( x, y+2*vyska/7, sirka, 5*vyska/7 ); }//public Smrk( int x, int y, int sirka, int vyska )
Když už budeme mít definovaný takovýto univerzální konstruktor, můžeme definice zbylých dvou konstruktorů silně zjednodušit a definovat je ve tvaru: public Smrk() { this( 0, 0, 50, 70 ); }//public Smrk() public Smrk( int x, int y ) { this( x, y, 50, 70 ) }//public Smrk( int x, int y )
Při definici bezparametrického konstruktoru bychom mohli jít ještě dál a definovat jej ve tvaru: public Smrk() { this( 0, 0 ); }//public Smrk()
Tím bychom zavolali konstruktor, kterému se zadávají pouze souřadnice a ten by zavolal konstruktor, jemuž se zadávají všechny čtyři parametry. Úkol: Vyzkoušejte definici „jednodušších“ konstruktorů volajících obecnější konstruktor prostřednictvím klíčového slova this i ve svých třídách Snehulak, Domek a Panak.
2.6 Syntaktické definice Poznámka: Tato kapitola trochu odbočuje od vlastního výkladu. Chtěl bych vás v ní seznámit se způsobem
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 13 z 41
2.6. Syntaktické definice
Strana 14 z 41
zápisu syntaktických definic, pomocí nichž lze jednoznačně popsat, jak má vysvětlovaná konstrukce vypadat. Možná bude některým z vás připadat těžká. Pokud se vám bude zdát, že je příliš abstraktní, klidně ji přeskočte a vraťte se k ní později, až si budete chtít ujasnit, jak si máte nějakou syntaktickou definici „přeložit“.
Při popisu syntaxe programových konstrukcí (syntaxe = souhrn pravidel, jak konstrukci zapsat) nebývá slovní popis optimálním způsobem vyjádření, protože se při něm často ztrácejí cenné informace v záplavě okolních slov. V programátorském světě se proto používají jiné druhy popisu. Jedním z nich jsou syntaktické definice. Ty budu používat i já. V syntaktických definicích je třeba rozlišit, co se z nich má do programu „opsat“, co pouze zastupuje nějaký objekt a co je pouze pomocný vyjadřovací prostředek pro popis struktury dané konstrukce. V syntaktických definicích, které budu v tomto kurzu používat, uvedu vždy na prvním řádku červeně název popisované konstrukce a na dalších, odsazených řádcích pak popíšu vlastní definici. V ní budu používat následující prvky: modře Modrou barvu budu používat pro ty části konstrukce, které se mají do výsledného programu opsat (např. pro složené závorky ohraničující tělo konstruktoru či třídy nebo pro čárku oddělující jednotlivé parametry v seznamu). název
Černě a pro vyšší odlišení ještě kurzivou budu psát názvy prvků, které se v definici vyskytují. Místo nich pak do programu napíšete příslušný prvek.
[]
Červené hranaté závorky budou uzavírat tu část konstrukce, která se v ní může, ale také nemusí vyskytovat.
…
Červená výpustka bude následovat za prvkem, který se může v konstrukci vyskytovat opakovaně.
{}
Červené složené závorky budou uzavírat skupinu prvků, s nimiž budu chtít v definici pracovat jako s celkem – např. za ně budu chtít vložit výpustku naznačující, že celá skupina se může opakovat.
|
Červené svislítko bude mít funkci nebo, která říká, že ve výsledné konstrukci se může objevit buď prvek vlevo od něj anebo prvek vpravo od něj. Ne však oba zároveň (to bychom museli zapsat jinak).
Definici konstruktoru bychom podle těchto pravidel zapsali následovně: Konstruktor:
[ modifikátor ]… název_třídy ( [ definice_parametru [ , definice_parametru ]… ] ) { [ příkaz ]… } Definice_parametru:
typ název
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 14 z 41
2.7. Dokumentační komentáře
Strana 15 z 41
Definici interpretujeme tak, že na počátku se může, ale nemusí vyskytovat modifikátor (zatím známe pouze modifikátor public, ale je jich víc). Modifikátorů dokonce může být i víc. Za modifikátorem následuje název třídy, jejíž instance konstruktor vytváří a za ním pak otevírací kulatá závorka uvozující seznam případných parametrů. Za ní může, ale nemusí být uvedena definice použitého parametru. Za definicí prvního parametru mohou být i definice dalších parametrů, ale každá z nich již musí být od předchozí definice oddělena čárkou. Za seznamem parametrů napíšeme zavírací kulatou závorku a za ní otevírací složenou závorku uvozující tělo konstruktoru. V těle konstruktoru nemusí být nic, ale může tam být i několik příkazů. Tělo ukončí uzavírací složená závorka. V definici konstruktoru se vyskytuje prvek definice_parametru. Ten vytvoříme tak, že uvedeme typ parametru a za ním jeho název. Abychom si ukázali použití červených složených závorek a svislítka, rozebereme si ještě definici identifikátoru: Identifikátor:
{ písmeno | _ | $ } [ písmeno | _ | $ | číslice ]… Tato definice je však nešikovná a uvedl jsem ji pouze proto, abych v ní mohl použít i složené závorky. V praxi bychom identifikátor definovali asi následovně: Identifikátor:
zobecněné_písmeno [ zobecněné_písmeno | číslice ]… Zobecněné_písmeno:
písmeno | _ | $ Tato definice říká, že identifikátor musí začínat zobecněným písmenem, za ním může následovat libovolný počet zobecněných písmen a číslic
2.7 Dokumentační komentáře Každá nová metoda by měla být doplněna o dokumentační komentář, který umístíme těsně před její hlavičku a ve kterém popíšeme, co metoda dělá, jaké požaduje parametry a co případně vrací. Měli bychom tak učinit i v případě právě definovaného konstruktoru. V automaticky generovaném zdrojovém souboru je u bezparametrického konstruktoru komentář již připraven. Nechám na vás, zda jej zkopírujete nebo zda vytvoříte nový. Definujete-li konstruktor s parametry, opíše se dokumentační komentář do horní poloviny dialogového okna. Aby k tomu však opravdu došlo, nesmí být v celém souboru v žádném komentáři ani identifikátoru jediné písmeno s diakritikou. Jakmile se tam nějaké objeví, přestanou se dokumentační komentáře v dialogových oknech pro zadání parametrů opisovat. Zároveň se přestanou uvádět i názvy zadávaných parametrů. Proto do doby, než tuto chybu autoři opraví, nepoužívejte v komentářích diakritiku.
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 15 z 41
2.7. Dokumentační komentáře
Strana 16 z 41
Poznámka: Najít zapomenutou čárku či háček bývá v delších programech opravdu těžké. Proto je občas vhodné použít nějaký nástroj, který všechna diakritická znaménka z textu odstraní (bohužel je odstraní i z textových řetězců, ale to již je daň za pohodlí). Já k tomuto účelu používám textový editor PSPad, který se s vámi baví česky, umí zvýraznit syntaxi javovských programů, má řadu nejrůznějších vymožeností (například je schopen do souboru bez diakritiky znovu vrátit háčky a čárky nad písmeny) a můžete si jej zdarma stáhnout na adrese http://pspad.zde.cz.
Dokumentační komentáře však neslouží pouze k tomu, aby se jejich obsah vypsal do nějakých dialogových oken. Ony slouží opravdu k vytvoření dokumentace. O tom se můžete přesvědčit např. tak, že rozbalíte seznam na pravém okraji panelu s tlačítky a místo dosavadní položky Implementace (zdrojový kód) vyberete položku Dokumentace (popis rozhraní) (viz obr. 2.14). BlueJ pak zavolá program, který je součástí JDK a který z vašich dokumentačních komentářů vyrobí HTML soubor efektně dokumentující vaši třídu. Tato autodokumentační schopnost Javy je jednou z jejích velice příjemných vlastností. Prozatím se jí však nebudeme podrobněji zabývat a vrátíme se k ní na konci této kapitoly a pak pokaždé, když se naučíme další rysy, o nichž se můžeme z dokumentace něco dozvědět. Prozatím se spokojíme s tím, že dokumentační komentáře metod se opisují do dialogových oken pro zadávání jejich parametrů.
Pomocné značky Jak jste si mohli v dialogových oknech volaných metod všimnout, v dokumentačních komentářích se používá několik speciálních značek. Prozatím jsme se setkali se značkou @param uvozující popis parametru a se značkou @return uvozující popis návratové hodnoty. (Časem se naučíme další.) V dialogovém okně vám možná tyto značky překáží, ale přesto bych vám radil, abyste je používali. Až se na konci této kapitoly k dokumentaci vrátíme, ukážu vám, jak se v ní používání těchto značek projeví. Podívejme se nyní na možnou podobu definice tří uvedených konstruktorů: /** * Konstruktor pro objekty tridy Smrk, který umožní nastavit * souradnice a rozmery vytvareneho obrazce. * Souradnicemi objektu se pritom rozumi souradnice * leveho horniho rohu opsaneho ctverce. * * @param x x-ova souradnice, x>=0, x=0 ma levy okraj platna * @param y y-ova souradnice, y>=0, y=0 ma horni okraj platna * @param sirka sirka obdelniku, sirka > 0 * @param vyska vyska obdelniku, vyska > 0 */ public Smrk( int x, int y, int sirka, int vyska ) { new Trojuhelnik( x+sirka/5, y, 3*sirka/5, 3*vyska/7 ); new Trojuhelnik( x+sirka/10, y+vyska/7, 4*sirka/5, 4*vyska/7 ); new Trojuhelnik( x, y+2*vyska/7, sirka, 5*vyska/7 ); }// public Smrk( int x, int y, int sirka, int vyska ) /** * Konstruktor pro objekty tridy Smrk, který umí nastavit J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 16 z 41
2.8. Definice atributů
Strana 17 z 41
* pocatecni pozici objektu. Velikost je implicitní. * Souradnicemi objektu se pritom rozumi souradnice * leveho horniho rohu opsaneho ctverce. * * @param x x-ova souradnice, x>=0, x=0 ma levy okraj platna * @param y y-ova souradnice, y>=0, y=0 ma horni okraj platna */ public Smrk( int x, int y ) { this( x, y, 50, 70 ); }// public Smrk( int x, int y ) /** * Bezparametricky konstruktor pro objekty tridy Smrk. * Nakresli objekt standardni velikosti se souradnicemi [0;0]. */ public Smrk() { this( 0, 0, 50, 70 ); }//public Smrk()
2.8 Definice atributů Kdybychom zůstali u dosavadní podoby definice konstruktorů, tak bychom toho s našimi smrčky moc dělat nemohli. Jednotlivé trojúhelníky se sice nakreslí, ale pak již s nimi nic dalšího dělat nemůžeme (vynechávám prohlížení instancí). Abychom tyto pomocné trojúhelníky mohli ještě někdy o něco požádat (např. o to, aby se přesunuly), musíme si někde zapamatovat odkaz na ně. Potřebujeme proto definovat atributy instancí, do nichž budeme potřebné informace ukládat. Atributy definujeme skoro stejně jako parametry. Neuvádějí se však v žádné hlavičce, ale v těle třídy vně těl jejích metod. Aby se nám kód lépe četl, umísťují se definice atributů v těle třídy většinou před definice metod tak, jak to napovídá komentář ve zdrojovém souboru. I v definici atributu musíme uvést nejprve typ atributu a pak jeho identifikátor (název). Oproti definici parametru máme navíc ještě dvě možnosti: před typ atributu můžeme vložit modifikátory, které blíže specifikují některé vlastnosti definovaného atributu, dokážeme-li určit počáteční hodnotu atributu (tj. nepotřebujeme-li k jejímu zjištění nějaké parametry zadávané až při volání konstruktoru), můžeme za název atributu přidat rovnítko a za ním počáteční hodnotu zadat. Celou definici atributu ukončíme středníkem. Syntaktickou definici definice atributu bychom mohli zapsat následovně: Definice atributu:
[ modifikátor ]… typ název [ = počáteční_hodnota ] ; Prozatím jsem se setkávali pouze s modifikátorem public, který oznamoval, že příslušnou třídu či metodu mohou používat všichni. Atributy jsou však považovány za soukromou věc každé třídy, ve
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 17 z 41
2.8. Definice atributů
Strana 18 z 41
které nemá nikdo cizí mít šanci se hrabat. Které atributy je třída ochotna zveřejnit, k těm poskytne příslušné přístupové metody. Ostatní jsou její soukromou záležitostí. Vše, co chceme deklarovat jako soukromou věc třídy, označujeme modifikátorem private. Dohodněme se, že všechny atributy budeme označovat vždy jako private. Jedinou výjimkou mohou být konstanty, protože ty nemá stejně nikdo šanci nijak změnit. Vynechám-li kvůli úspoře místa dokumentační komentáře (v programu je však nevynechávejte), mohla by definice třídy Smrk s potřebnými atributy a třemi výše popsanými konstruktory vypadat např. takto: public class Smrk { //== ATRIBUTY INSTANCI ========================================================= private Trojuhelnik horni; private Trojuhelnik stredni; private Trojuhelnik dolni; //== KONSTRUKTORY ============================================================== public Smrk( int x, int y, int sirka, int vyska ) { horni = new Trojuhelnik( x+sirka/5, y, 3*sirka/5, 3*vyska/7 ); stredni=new Trojuhelnik( x+sirka/10, y+vyska/7, 4*sirka/5, 4*vyska/7 ); dolni = new Trojuhelnik( x, y+2*vyska/7, sirka, 5*vyska/7 ); }//public Smrk( int x, int y, int sirka, int vyska ) public Smrk( int x, int y ) { this( x, y, 50, 70 ); }//public Smrk( int x, int y ) public Smrk() { this( 0, 0, 50, 70 ); }//public Smrk() }//public class Smrk
Nyní třídu přeložte a nechte zkonstruovat jednu její instanci. Když v místní nabídce této instance zadáte příkaz Prohlížet, otevře se známé prohlížecí okno a v něm se opravu objeví ony tři atributy, které jsme ve třídě definovali. Jak vidíte, dokonce se o nich dozvíme, že jsou soukromé (private) a že jsou instancemi typu Trojuhelnik. Protože jsou tyto atributy instancemi objektového typu, neukáže se nám žádná hodnota, jak jsme tomu byli zvyklí u celých čísel, ale prohlížeč nám pouze oznámí, že obsahem atributu je odkaz na objekt. My se však můžeme na tento objekt podívat zblízka. Jakmile totiž klepnete na některý z objektových atributů, „obživne“ vpravo tlačítko Prohlížet (viz obr. 2.10) a po stisknutí tohoto tlačítka se otevře okno prohlížeče, které nám umožní do útrob daného atributu nahlédnout.
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 18 z 41
2.8. Definice atributů
Strana 19 z 41
Obrázek 2.10: Prohlížení instance s atributy objektových typů.
Úkol 1: Otevřete prohlížecí okna pro všechny trojúhelníky, z nichž je stromek sestaven, a ověřte, že hodnoty jejich atributů odpovídají tomu, co jsme zadávali v konstruktoru. Úkol 2: Definujte atributy i pro svoje třídy Snehulak, Domek a Panak a upravte příslušně i konstruktory. Nechte pak vytvořit instance těchto třídy a prohlédněte si jejich atributy.
Možné důsledky zveřejnění atributů Jak jsem řekl, všechny atributy by měly být deklarovány jako soukromé. Ukažme si, co by se mohlo stát, kdyby tomu tak nebylo. Změňte např. deklaraci horního trojúhelníka a označte jej jako veřejný. Třídu znovu přeložte, vytvořte její instanci a podívejte se na ni prohlížečem. Klepněte nyní na horní trojúhelník. Vpravo se rozsvítí nejenom tlačítko Prohlížet, ale také tlačítko Získat odkaz (viz obr. 2.11).
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 19 z 41
2.9. Definujeme vlastní metodu
Strana 20 z 41
Obrázek 2.11: Prohlížeč umí předat odkaz na veřejný atribut objektového typu
Stiskněte toto tlačítko a v zásobníku odkazů se objeví nový odkaz nazvaný horni. Nyní otevřete místní nabídku tohoto odkazu a zadejte např. příkaz posunVpravo(). Vrchní část stromku, na jejíž instanci odkaz vede, se poslušně přesune požadovaným směrem. Můžete ji samozřejmě zadat jakýkoliv jiný příkaz (např. smaž) a ona poslechne. Předpokládám, že možné důsledky zveřejnění atributů jsou z tohoto příkladu jasné. Protože je atribut veřejný, může k němu přistupovat kdokoliv. Je úplně jedno, zda nevhodnou manipulací s atributem poškodí vaši instanci záměrně nebo omylem – důsledkem bude poškozená instance.
2.9 Definujeme vlastní metodu Vím, že název této části zcela nesedí, protože jsme již vlastní metodu definovali (konstruktor je také přeci také metoda, i když zvláštní), ale věřím, že pochopíte, co jsem jím chtěl říci. Zkusíme si definovat vlastní metodu instance. Dohodněme se, že pro náš stromek nebudeme definovat žádné přístupové metody k jednotlivým trojúhelníkům, protože pro to nemáme žádný důvod. Není proč někomu umožňovat získat odkaz na některý z trojúhelníků, ani tento trojúhelník změnit. První metodu, kterou bychom měli pro náš stromek definovat, je metoda kresli(), protože ji většina ostatních metod bude potřebovat. Její definice bude jednoduchá: nemá žádné parametry ani nic nevrací, takže bude mít jednoduchou hlavičku, a díky jednoduchosti naší instance i jednoduché tělo: /** * Nakresli stromek na platno. */ public void kresli() { J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 20 z 41
2.9. Definujeme vlastní metodu
Strana 21 z 41
horni.kresli(); stredni.kresli(); dolni.kresli(); }//public void kresli()
V těle metody si všimněte, jak se v programu zapisuje příkaz k zaslání zprávy nějaké instanci: napíše se název proměnné, v níž je uložen odkaz na tuto instanci, za název se napíše tečka, za tečku název metody realizující reakci na danou zprávu a za název pak kulaté závorky se seznamem hodnot předávaných parametrů (voláme-li bezparametrickou metodu, budou závorky prázdné). Celý příkaz ukončíme středníkem. Úkol: Definujte k této metodě doplňkovou metodu Smaz(). Konstruktory s parametry jsme již zvládli, takže jistě zvládneme i běžné metody s parametry. Ukažme si např. definici metody posunVpravo(int). Celý smrk bychom mohli posunout tak, že bychom postupně posunuli jednotlivé trojúhelníky. Vyvoláte-li však posun trojúhelníků od horního ke spodnímu, zjistíte, že stromek vypadá po menším posunutí divně. Je to proto, že trojúhelník se při posunu nejprve smaže a pak se nakreslí v nové pozici. Při tomto mazání (nakreslí se barvou plátna) pak může zničit obrázek horního trojúhelníku. Prohodíme-li ale pořadí volání jednotlivých posunů, bude vše v pořádku. /** * Posune stromek o zadany pocet bodu vpravo, * pri zapornem parametru vlevo. * * @param n pocet bodu, o ktere se smrcek posune */ public void posunVpravo( int n ) { dolni.posunVpravo( n ); stredni.posunVpravo( n ); horni.posunVpravo( n ); //Pri vodorovnem posunu nemuze odmazani horniho patra // poskodit dolni patro => neni treba nic znovu kreslit }//public void posunVpravo( int n )
Dovolil bych si vás upozornit na zmínku o parametru, která se objevuje v dokumentačním komentáři. Znovu připomínám: zvykněte si důsledně zadávat dokumentační komentáře i se všemi vyhlašovanými parametry. Úkol 1: Doplňte definici metody posunDolu(int). Myslete však na to, že po některých posunech bude třeba něco znovu nakreslit. Úkol 2: Doplňte obdobné definice i pro svoje třídy Snehulak, Domek a Panak.
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 21 z 41
2.10. Kvalifikace a klíčové slovo this
Strana 22 z 41
2.10 Kvalifikace a klíčové slovo this Název proměnné následovaný tečkou je označován jako kvalifikace metody, protože blíže určuje (kvalifikuje), o čí metodu se jedná, tj. které instance je ta metoda (které instanci posíláme zprávu). Technicky vzato, volanou metodu musíme mimo jiné kvalifikovat i proto, že potřebujeme, a y mohla pracovat s atributy metodami dané instance, a kdybychom metodu nekvalifikovali, nebylo by jasné, s čími atributy má pracovat. Nyní hned trochu vyvrátím to, co jsem právě řekl. Překladač totiž ví, že volat nekvalifikovanou metodu instance je nesmysl, takže pokud tak učiním, tj. pokud v programu zavolám nekvalifikovanou metodu instance, pokusí se ji kvalifikovat tou instancí, jejíž metodu právě překládá. Podaří-li se mu to, je spokojen. Nepodaří-li se mu to, tj. není-li tato metoda pro danou instanci definována, ohlásí chybu překladu. Ukažme si to na příkladu. V minulé kapitole jsme definovali metodu posunVpravo(int). Aby byla souprava metod symetrická, zkusme doplnit i metodu posunVlevo(int). Vzhledem k tomu, že posun vlevo je záporně zadaný posun vpravo, může být řešení velice jednoduché: /** * Posune stromek o zadany pocet bodu vlevo, * pri zapornem parametru vpravo. * * @param bodu pocet bodu, o ktere se smrcek posune */ public void posunVlevo( int bodu ) { //Pro posun vlevo musime zadat zapornou hodnotu posunVpravo( -bodu ); }//public void posunVlevo( int bodu )
Příkaz v těle metody bychom mohli „převyprávět“: zavolej metodu posunVpravo(int) té instance, kterou já mám posunout vlevo. Situaci, kdy si překladač kvalifikaci domyslí, označujeme jako implicitní kvalifikace, na rozdíl od explicitní kvalifikace, při níž programátor kvalifikuje metodu (nebo jinou část programu) sám. Řada programátorů nerada vidí používání nekvalifikovaných (přesněji implicitně kvalifikovaných) atributů a metod a dává přednost důsledné explicitní kvalifikaci. K té slouží klíčové slovo this, které vždy zastupuje tu instanci, v jejíž metodě toto klíčové slovo použijeme. S použitím klíčového slova this bychom předchozí metodu zapsali: public void posunVlevo( int bodu ) { //Pro posun vlevo musime zadat zapornou hodnotu this.posunVpravo( -bodu ); }//public void posunVlevo( int bodu )
Klíčové slovo this nám umožňuje kvalifikovat nejenom metody, ale i atributy. Při definici metod s parametrem se např. často stane, že nám jako nejvhodnější název parametru připadá název atributu, jehož hodnotu tento parametr nastavuje. V definici metody je pak ale třeba rozhodnout, o který z obou objektů se v tom kterém případě jedná.
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 22 z 41
2.11. Metody vracející hodnotu
Strana 23 z 41
Překladač se rozhoduje podle hesla „Bližší košile než kabát.“ Při výběru objektu, který daný identifikátor označuje, dá přednost parametru před atributem, protože parametr byl definován „právě tady“ v hlavičce metody, kdežto atribut je definován kdesi zcela mimo metodu. Budeme-li chtít překladač přesvědčit, že v tomto případě máme na mysli atribut, musíme atribut kvalifikovat klíčovým slovem this. Kdybychom v naší třídě měli např. atribut x, mohli bychom jeho nastavovací metodu definovat následovně: public void setX( int x ) { this.x = x; }//public void setX( int x )
2.11 Metody vracející hodnotu Třídy obrazců, s nimiž jsme doposud pracovali, nabízely pro svoje atributy přístupové metody, které umožňovaly zjistit či nastavit jejich hodnotu. Podívejme se, jak bychom takové metody realizovali v naší třídě Smrk. Jistě budete souhlasit s tím, že by nebylo moudré nabídnout přístup k jednotlivým trojúhelníkům tvořícím smrček. To by nám jej pak někdo mohl pěkně rozhodit. Měli bychom mu však umožnit zjistit aktuální polohu a velikost jednotlivých instancí, tj. jednotlivých smrků. K tomu potřebujeme definovat metodu, která bude vracet hodnotu. Taková metoda se od metod, které jsme definovali doposud, liší ve dvou věcech: v hlavičce má místo typu void uveden typ hodnoty, kterou vrací, před ukončení činnosti musí vrátit požadovanou hodnotu – k tomu slouží příkaz return, za který napíšeme výraz, jehož hodnotu bude metoda vracet. Ukažme si např. jak bychom definovali metody, které nám vrátí aktuální pozici obrazce vykresleného danou instancí. /** * Vraci y-ovou souradnici celeho smrku. * * @return y-ova souradnice smrku */ public int getY() { //y-ova souradnice horniho trojuhelniku //je zaroven y-ovou souradnici celeho smrku return horni.getY(); }//public int getY()
Použití metod vracejících hodnotu Metody vracející hodnotu můžeme zavolat kdekoliv, kde budeme vracenou hodnotu potřebovat. Když budete chtít např. spočítat plochu zabranou instancí, na níž odkazuje proměnná obrazec, spočtete ji podle vzorce:
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 23 z 41
2.12. Zapouzdření
Strana 24 z 41
int plocha = obrazec.getSirka() * obrazec.getVyska();
Když počítač narazí na takovýto výraz, zavolá nejprve metodu obrazec.getSirka(), zapamatuje si vrácenou hodnotu, pak zavolá metodu obrazec.getVyska(), opět si zapamatuje vrácenou hodnotu a obě zapamatované hodnoty spolu vynásobí. Výsledek pak uloží jako počáteční hodnotu právě definované proměnné plocha. Možnosti dosadit za neznámou hodnotu volání metody, která danou hodnotu zjistí a vrátí, můžeme využít i při výpočtu výšky celého smrku – příslušná metoda by mohla vypadat např. následovně: /** * Vrati vysku celeho obrazce. * * @return vyska smrku */ public int getVyska() { //Vysku spoctu jako rozdil y-vych souradnic //spicky a spodni hrany smrku return dolni.getY()+dolni.getVyska() - horni.getY(); }//public int getVyska()
2.12 Zapouzdření Takto jsme vlastně definovali přístupové metody k atributům, které vůbec neuchováváme. To je ale relativně časté. Tvůrci programů se občas rozhodnou, že některé atributy nestojí za to, aby si je instance pamatovaly, protože je možné je vždy v případě potřeby dostatečně rychle zjistit. Zvenku třídy, tj. při volání jejích přístupových metod, nemáme šanci zjistit, jestli třída uvnitř pracuje se skutečnými a nebo s vypočítanými atributy. A to je dobře. Jednou ze základních a velice ceněných vlastností objektově orientovaných programů je schopnost tzv. zapouzdření. Lidově bychom mohli zapouzdření charakterizovat heslem: „Nikdo nesmí mít šanci zjistit nic o tom, jak to dělám, že umím to, co umím.“ Takto osamoceně vyslovena vypadá možná tato zásada neurvale, ale věřte, že je to nejvíce ceněná vlastnost celého OOP. Čím jsou programy složitější, tím je důležitější, abychom ani omylem nemohli ovlivnit chod některé jiné části. V této souvislosti se seznámíme se dvěma novými termíny: Rozhraní třídy budeme chápat jako množinu informací, které o sobě třída zveřejní. Mezi rozhraní patří např. vše, co třída označí modifikátorem public. Implementace je způsob, jak je třída naprogramována. Do rozhraní bychom měli zařadit pouze to, co ostatní části programu o dané třídě opravdu musí vědět. Když jsme například chtěli, aby ostatní programy mohly naši třídu požádat o vytvoření instance, museli jsme zveřejnit její konstruktor. Budeme-li chtít, aby ostatní programy mohly zjistit, kde je právě daný smrk nakreslen, musíme zveřejnit metody, pomocí nichž mohou tuto informaci získat.
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 24 z 41
2.13. Lokální proměnné
Strana 25 z 41
Vše, co sice k implementaci požadovaných funkcí potřebuji, ale o čem se domnívám, že ostatní vědět nemusí, označím jako private. Nechci-li, aby ostatní části programu mohly pohybovat jednotlivými částmi smrčku bez mého vědomí, nesmím je k nim pustit – označím proto příslušné atributy jako private. Poznámka: Mezi public a private existují ještě mezistupně, ale o těch si povíme až si s objektovým programováním trochu více potykáte.
Do rozhraní se někdy počítají i informace, které z hlaviček nevyčtete, ale které by měly být uvedeny v dokumentaci. Sem patří informace o dalších podmínkách, které je třeba dodržet (např. že zadávané souřadnice vytvářeného tvaru musí být větší než 0, že instance metody Platno je jedináček apod.) o možných vedlejších efektech funkcí (např. co se stane, když obrazec „vycestuje“ z plátna) a řada dalších důležitých sdělení. Tento souhrn informací bývá označován jako kontrakt.
2.13 Lokální proměnné Když jsme již definovali metody, které vracejí hodnoty fiktivních atributů, zkusme definovat metody, které hodnoty těchto atributů nastavují. Definujme např. metodu setRozmer(int,int). Protože je náš smrk sestaven z několika trojúhelníků různých velikostí, není přepočet jejich nových velikostí právě jednoduchý. Budeme při něm navíc potřebovat použít některá čísla několikrát. Bylo by proto výhodné definovat nějaké lokální proměnné (Baltíkovy košíky), kam si budeme ukládat mezivýsledky. Lokální proměnné se definují naprosto stejně jako atributy. Jediným rozdílem je, že se definují uvnitř metod a že mimo jejich metodu o nich nikdo neví. Bude-li proto jiná metoda definovat stejně pojmenované lokální proměnné, budou možná stejně pojmenované, ale budou to naprosto jiné proměnné. Poznámka: Je to obdobné, jako když budete mít doma morče pojmenované Ferda (programátorsky: budete mít lokální proměnnou Ferda typu Morče) a váš kamarád na druhém konci města bude mít stejně pojmenované morče. Obě jsou to morčata, obě mají stejné jméno, ale nikdo nepředpokládá, že nakrmíte-li vašeho Ferdu, přestane mít kamarádův Ferda hlad. Stejně pohlížejte i na lokální proměnné metod.
Lokální proměnné mají ještě dvě důležité vlastnosti: Před jejich prvním použitím jim musíte přiřadit nějakou počáteční hodnotu. Neučiníte-li tak, ohlásí překladač chybu, protože odmítá vytvořit program, který by pracoval s nějakým smetím, jež by se zrovna nacházelo v paměti na místě, které by pro danou proměnnou vyhradil. Jakmile metodu opustíte, proměnná se zruší a při příštím spuštění metody se znovu vytvoří. Není proto možné uchovávat v lokálních proměnných cokoliv, co si potřebujeme pamatovat mezi jednotlivými voláními dané metody. K tomu musíte použít atributy.
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 25 z 41
2.14. Atributy třídy (statické atributy)
Strana 26 z 41
Takže nyní už všechno víme a můžeme začít programovat: /** * Nastavi novy rozmer stromku na platne. * * @param s nova sirka smrku * @param v nova vyska smrku */ public void setRozmer( int s, int v ) { //Zmenou velikosti celeho smrku se meni i pozice //jeho jednotlivych casti - je treba nastavit obe //Pri nastavovani muzeme vyjit z definice kontruktoru //Pripravime si casto pocitane vyrazy int s5 = s/5; int v7 = v/7; int x = getX(); int y = getY(); //Spocteme a nastavime novou pozici jednotlivych casti horni.setPozice ( x + s5, y ); stredni.setPozice( x + s/10, y + v7 ); dolni.setPozice ( x, y + v7*2 ); //Spocteme a nastavime horni.setRozmer ( 3 * stredni.setRozmer( 4 * dolni.setRozmer (
definitivni podobu casti s5, 3 * v7 ); s5, 4 * v7 ); s, 5 * v7 );
//Pri odmazavani dolnich dilu se muze umazat kus hornich horni.kresli(); stredni.kresli(); }//public void setRozmer( int s, int w )
Úkol 1: Definujte pro třídu Smrk2 ještě metodu setPozice(int,int). Úkol 2: Definujte obě metody i pro svoje třídy Snehulak, Domek a Panak.
2.14 Atributy třídy (statické atributy) Když jsme si v minulé kapitole hráli s geometrickými obrazci, ukazovali jsme si, že každý z nich poskytuje metody, které mohou pohnout se zadaným obrazcem o předem zadaný počet bodů. Tento počet byl uložen v atributu třídy nazvaném krok. Terminologická poznámka: Chceme-li ve zdrojovém kódu definovat nějaký atribut jako atribut třídy, přidáme mezi jeho modifikátory modifikátor static. Toť vše. Vzhledem k tomuto klíčovému slovu v deklaraci bývají atributy třídy často označovány jako statické atributy a atributy instancí jako nestatické atributy. Protože se tento termín oproti termínu „atributy třídy“ lépe skloňuje, budu jej v dalším textu často používat.
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 26 z 41
2.15. Metody třídy (statické metody)
Strana 27 z 41
Na rozdíl od atributů instancí, které můžeme inicializovat buď přímo v deklaraci nebo později v konstruktoru, pro inicializaci atributů třídy prozatím žádný konstruktor neznáme (existuje, ale do začátečnických kurzů přeci jenom nepatří). Zbývá nám tedy prozatím pouze inicializace v deklaraci. Naštěstí to však není žádné velké omezení, protože inicializovat můžeme i voláním nějaké metody, která potřebnou hodnotu nejprve spočítá. U statických atributů si proto můžeme pomoci metodou, jež bude potřebnou hodnotu vracet. V našich současných příkladech prozatím takovýto způsob inicializace nepotřebujeme, protože vystačíme s inicializací pomocí pevných hodnot. Až ji budeme potřebovat, tak vám to ještě připomenu. Úkol 1: Doplňte třídu Smrk o atribut krok, který bude obsahovat počet bodů, o které se obraz smrku posune po zavolání bezparametrických verzí posunových metod, a nadefinujme si hned metodu posunVlevo(). //== ATRIBUTY TRIDY ============================================================ private static krok = 50; //== OSTATNI METODY INSTANCI =================================================== /** * Posune obrazek smrku o krok bodu vlevo. */ public void posunVlevo() { //Pro posun vlevo musime zadat zapornou hodnotu posunVpravo( -krok ); }//public void posunVlevo()
Úkol 2: Doplňte třídu Smrk2 o metody posunVpravo(), posunNahoru() a posunDolu(). Úkol 3: Doplňte statický atribut a bezparametrické posunové metody i do svých tříd Snehulak, Domek a Panak.
2.15 Metody třídy (statické metody) Stejně jako atributy třídy existují i metody třídy. Jejich výhodou je, že je můžeme zavolat ještě před tím, než vznikne její první instance. Slouží proto často k přípravě prostředí, ve kterém následně instance vznikne, případně k definici metod, které nejsou na žádnou instanci vázány (takto je např. definována většina matematických funkcí). Jako metody třídy se (samozřejmě) definují také přístupové metody atributů třídy (i ty můžeme např. číst a nastavovat ještě před tím, než vznikne první instance dané třídy). Poznámka: Před chvilkou jsme si vysvětlovali, že atributy třídy můžeme inicializovat i prostřednictvím voJ02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 27 z 41
2.15. Metody třídy (statické metody)
Strana 28 z 41
lání metod. Protože se tyto atributy inicializují ještě před tím, než se třída poprvé použije, musíme k jejich inicializaci použít statických metod, protože jedině ty můžeme volat ještě před tím, než vznikne jakákoli v instance.
Úkol 1: V naší třídě Smrk i ve vašich třídách Snehulak, Domek a Panak již je definován statický atribut krok. Definujme pro něj přístupovou metodu getKrok(): /** * Vraci velikost kroku, o kterou se posune obrazek smrku * pri volani bezparametrickych posunovych metod. * * @return velikost kroku v bodech */ public static int getKrok() { return krok; }//public static int getKrok()
Úkol 2: Doplňte stejnojmennou metodu do svých tříd Snehulak, Domek a Panak. Upozornění: Jak jsem řekl, metody třídy nezávisejí na žádné instanci a můžeme je volat ještě před tím, než první instance vznikne. Je proto logické, že v metodách třídy nemůžeme používat atributy a metody instancí, přesněji řečeno atributy a metody instancí kvalifikované implicitně nebo explicitně klíčovým slovem this. Překladač totiž nemá žádnou informaci o tom, která instance by se v daném okamžiku mohla za this skrývat. Nic nám však nebrání vytvořit uvnitř metody novou instanci a volat pak její metody, protože ty již můžeme kvalifikovat konkrétní, existující instancí. Někdy si to ukážeme.
Kvalifikace atributů a metod třídy I metody třídy je potřeba kvalifikovat, protože i u nich překladač potřebuje vědět, čí metodu překládá, aby se pak mohl obrátit na správné atributy. Můžeme je sice kvalifikovat instancí, ale jak jsme si před chvílí řekli, metody třídy je možno volat ještě před vznikem první instance (např. k tomu, abych nastavil velikost kroku při volání bezparametrických posunových metod žádnou instanci nepotřebuji). Pro jejich kvalifikaci nemůžeme použít ani klíčové slovo this, protože i to je určené k získání odkazu na instanci. Jak si jistě domyslíte, onou instancí, jejíž atributy a metody definované třídě slouží, je vlastně celá třída. Asi vás proto nijak nepřekvapí, když vám prozradím, že metody třídy je možné kvalifikovat názvem třídy. Odtud by pak již mělo být vše jasné. Pokud byste tedy např. chtěli ve svém programu získat plátno, abyste je mohli o něco požádat, zadáte příkaz: Platno platno = Platno.getPlatno();
Tento příkaz definuje novou proměnnou (možná atribut, možná lokální proměnnou – to bychom poznali až podle okolního programu), která je odkazem na instanci třídy Platno a jmenuje se platJ02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 28 z 41
2.15. Metody třídy (statické metody)
Strana 29 z 41
no. V její deklaraci ji ihned přiřazujeme počáteční hodnotu, kterou získáme tak, že zavoláme metodu getPlatno(), která je (jak již víme) metodou třídy Platno a vrací odkaz na její jedinou instanci. Ukažme si, jak bychom mohli takovouto proměnnou použít v programu. Předpokládejme, že máme ve třídě definovanou metodu setBarva(String) (tu byste určitě pro smrk či sněhuláka definovat dokázali – prostě nastavíte pro všechny trojúhelníky, resp. elipsy zadanou barvu). Definujme metodu schovejVPozadí(), která přebarví danou instanci na barvu pozadí použitého plátna. Definice by mohla vypadat následovně: /** * Prebarvi obrazek smrku barvou pozadi platna. */ public void schovejVPozadi() { //Metodu tridy kvalifikujeme tridou Platno platno = Platno.getPlatno(); //Metodu instance kvalifikujeme instanci String pozadi = platno.getBarvaPozadi(); horni.setBarva( pozadi ); stredni.setBarva( pozadi ); dolni.setBarva( pozadi ); }//public void schovejVPozadi()
Názvem třídy můžeme kvalifikovat nejenom metody třídy, ale i její atributy. Ukažme si to na příkladu metody setKrok(int), jejíž parametr bude mít stejný název jako nastavovaný atribut třídy: /** * Nastavi novou velikost kroku, o kterou se posune obrazek * smrku pri volani bezparametrickych posunovych metod. * * @param krok nastavovana velikost kroku v bodech */ public static void setKrok( int krok ) { //Atribut krok kvalifikujeme názvem tridy Smrk.krok = krok; }//public static void setKrok( int krok ) Poznámka: Překladač není žádný hlupák. Objeví-li v kódu nekvalifikovaný odkaz na atribut nebo metodu třídy, nebude se je samozřejmě pokoušet hloupě kvalifikovat klíčovým slovem this, jak to dělal u atributů a metod instancí, ale rozumně se je pokusí kvalifikovat názvem třídy, v jejímž těle se daný kód nachází. Kdybychom tedy v předchozí metodě použili parametr k a přiřazovací příkaz měl tvar: krok = k; překladač by identifikátor krok iniciativně kvalifikoval jako Smrk.krok, což je to, co jsme chtěli.
Úkol: Doplňte stejnojmennou metodu do svých tříd Snehulak, Domek a Panak.
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 29 z 41
2.16. Konstanty a literály
Strana 30 z 41
2.16 Konstanty a literály V programech často používáme nejrůznější „magické hodnoty“, které se v průběhu programu nemění. Budeme-li chtít např. pracovat s počtem dnů v týdnu, budeme neustále používat číslo 7. Problém nastane, když se při některé z pozdějších úprav rozhodneme, že místo počtu dnů v celém týdnu bude pro náš program výhodnější používat pouze počet pracovních dnů, tj. 5 (alespoň prozatím to tak je). Taková úprava pak znamená prolézt celý program a všechny sedmičky nahradit pětkami. Již samotná tato představa je dostatečně nepříjemná. Noční můrou se ale stane, pokud je program opravdu rozsáhlý a navíc je v něm řada různých „sedmiček“ – některé sedmičky budou např. znamenat, že v červenci začínají prázdniny a další sedmičky budou oznamovat, že pracujeme od 7 hodin ráno. Rozumní programátoři proto takovéto magické hodnoty zásadně nepoužívají a dávají přednost pojmenovaným konstantám. Ty se v Javě definují stejně jako proměnné, pouze se mezi jejich modifikátory uvede klíčové slovo final. Konstantám můžeme přiřadit hodnotu pouze jednou a již nikdy ji nemůžeme změnit: statickým konstantám přiřadíme jejich hodnotu hned v deklaraci, nestatickým konstantám, které nemají svoji hodnotu přiřazenou v deklaraci, musíme přiřadit hodnotu v konstruktoru. Terminologická poznámka: Tyto „magické hodnoty“ se označují jako literály. Literál je konstanta zapsaná svoji hodnotou – např. 7 (celočíselný literál), "Ahoj" (řetězcový literál) apod. Naproti tomu konstanty, o nichž jsme právě hovořili, se označují jako pojmenované konstanty, protože ve své definici dostanou jméno, kterým se na ně v programu odvoláváme. Budu-li v dalším textu hovořit o konstantách, bud tím vždy myslet pojmenované konstanty. Pokud bych chtěl hovořit o literálech, vždy to výslovně uvedu. Poznámka o dobrých mravech: Z číselných literálů se doporučuje používat pouze hodnoty 0 a 1. Ostatní hodnoty je lepe definovat jako pojmenované konstanty. Dokonce i nuly a jedničky se mají používat pouze v situacích, kdy tyto hodnoty neoznačuji nic, co by se mohlo v některé z příštích verzí programu změnit – např. v současné době mám jen jedno kolo (auto, peněženku, manželku, …), ale dokážu si představit situaci, kdy se tato jednička změní. Obdobně řetězcové literály je vhodné používat pouze v situacích, kdy se daný řetězec použije pouze jednou (např. v chybovém hlášení). Chcete-li však program lokalizovat do více jazyků, je vhodné i jednou použité textové řetězce pojmenovat a definovat všechny na jednom místě, kde je lze snadno nahradit jejich překlady.
Rozšiřme počet konstruktorů smrku o konstruktor, který umožní zadat i jeho barvu. Definujme přitom konstantu BARVA_0, v níž bude uchována implicitní barva smrku, kterou použijeme ve chvíli, kdy nebude jeho barva zadána. Počátek programu s příslušnou konstantou a konstruktory by mohl vypadat následovně (dokumentační komentáře a dříve definované metody a atributy pro úsporu místa opět vynechávám): public class Smrk J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 30 z 41
2.17. Předání parametru objektového typu
Strana 31 z 41
{ //== VEREJNE KONSTANTY ========================================================= public static final String BARVA_0 = "zelena"; // ... preskoceno ... //== KONSTRUKTORY ============================================================== public Smrk( int x, int y, int s, int v, String b ) { horni = new Trojuhelnik( x+s/5, y, 3*s/5, stredni=new Trojuhelnik( x+s/10, y+v/7, 4*s/5, dolni = new Trojuhelnik( x, y+2*v/7, s, }//public Smrk( int x, int y, int sirka, int vyska,
3*v/7, 4*v/7, 5*v/7, String
b ); b ); b ); Barva )
public Smrk( int x, int y, int sirka, int vyska ) { this( x, y, 50, 70, BARVA_0 ); }//public Smrk( int x, int y, int sirka, int vyska ) // ... preskoceno ... }// public class Smrk
Jak jste si jistě všimli, definoval jsem konstantu jako veřejnou. Když jsme se bavili o zapouzdření, říkal jsem, že atributy mají být soukromé a že veřejné mohou být pouze konstanty, které nikdo nemůže změnit. Nyní ten případ nastal. Protože se domnívám, že konstantu BARVA_0 může okolí za jistých okolností využít, definoval jsem ji jako veřejnou. Poznámka: Jako neměnné lze považovat číselné, logické a řetězcové konstanty. U konstant objektových typů to však nemusí platit. Kdybychom např. označili atribut horni za konstantu, znamenalo by to, že se nemění hodnota atributu, tj. že odkazuje stále na stejnou instanci. Nijak tím ale neovlivníme to, co se děje s danou instancí (jestli s ní např. někdo nehýbe). Závěr: Nedeklarujte atributy objektových typů (s výjimkou konstant typu String) jako veřejné – alespoň do doby, než se naučíte zabezpečit, aby s nimi nikdo nemohl dělat nepravosti.
Úkol: Doplňte do třídy Smrk2 konstantu BARVA_0 spolu s metodami getBarva() a setBarva(String).
2.17 Předání parametru objektového typu Poznámka: Tato podkapitola by teoreticky patřila ještě do první kapitoly, kde jsme si ukazovali, co vše nám prostředí BlueJ nabízí. Tehdy mne však ještě nenapadl příklad, jak vám možnost předání parametru objektového typu ukázat. Přitom stačilo např. ukázat, jak bychom jednomu geometrickému tvaru přiřadili barvu jiného geometrického tvaru. Omlouvám se a již to napravuji.
Zkusme náš smrk přebarvit a pak mu opět vrátit implicitní barvu, která je uchovávána v konstantě BARVA_0 (přesněji řečeno v řetězci, na nějž tato konstanta odkazuje). Provádějte se mnou: J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 31 z 41
2.17. Předání parametru objektového typu
Strana 32 z 41
1.
Zřiďte novou instanci třídy Smrk.
2.
Zavoláním metody setBarva( "cerna" ) smrk přebarvěte.
3.
Otevřete pro instanci smrku okno prohlížeče (např. zadejte v místní nabídce odkazu na instanci příkaz Prohlížet).
4.
Klepněte v okně prohlížeče na řádek s konstantou a stiskněte poté tlačítko Získat odkaz (viz obr. 2.12). V zásobníku odkazů se objeví odkaz na naši řetězcovou konstantu.
Obrázek 2.12: Získání odkazu na konstantu objektového typu 5.
Zavolejte znovu metodu setBarva(String), klepněte do vstupního pole pro zadání parametru a pak v zásobníku odkazů klepněte na odkaz na konstantu BARVA_0 – odkaz na instanci se přenese do vstupního pole (viz obr. 2.13).
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 32 z 41
2.18. Dokumentace
Strana 33 z 41
Obrázek 2.13: Předej odkaz jako parametr 6.
Potvrďte své zadání stiskem OK a přesvědčete se, že se stromek opět vybarvil implicitní barvou.
2.18 Dokumentace Končíme kapitolu o základech kódování definic tříd, jejich atributů a metod. Na počátku kapitoly jsem vám slíbil, že se na konci ještě jednou vrátím k otázce dokumentace. Ukážeme si, jaké prostředky nám Java nabízí k tomu, abychom s relativně minimální námahou mohli vytvářet poměrně efektní a profesionálně vyhlížející dokumentaci svých výtvorů. Již jsme si řekli, že rozbalíte-li v okně editoru seznam na pravém okraji panelu s tlačítky a vyberete-li místo dosavadní položky Implementace (zdrojový kód) položku Dokumentace (popis rozhraní) (viz obr. 2.14), objeví se v okně editoru místo kódu jeho dokumentace (viz obr. 2.15).
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 33 z 41
2.18. Dokumentace
Strana 34 z 41
Obrázek 2.14: Přepnutí editoru na zobrazení dokumentace
Při prvním pokusu to bude sice chvilku trvat, protože BlueJ musí nejprve zavolat program javadoc, který je součástí JDK a který z vašich dokumentačních komentářů vyrobí HTML soubor efektně dokumentující vaši třídu. Při příštím přepnutí bude již vše okamžité (samozřejmě nezměníte-li mezi tím kód třídy).
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 34 z 41
2.18. Dokumentace
Strana 35 z 41
Obrázek 2.15: Vytvořená dokumentace třídy
Projděte si postupně celou dokumentaci a podívejte se, jak se jednotlivé informace zadávané do dokumentačních komentářů promítnou do výsledné dokumentace třídy. Ta je rozdělena do několika sekcí: Nejprve je třída představena. Informace, které lze vyčíst z této části, oceníte po přečtení dalších dvou kapitol. Prozatím si zapamatujeme, že zde nalezneme jméno třídy. Do následující části se zkopírují informace z dokumentačního komentáře před hlavičkou třídy. Přitom informace zadané za značkami @version a @author dostanou své vlastní nadpisy. Ve třetí části je uveden seznam atributů. Tato část v naší dokumentaci chybí, protože jsme všechny atributy prohlásili za soukromé, takže je program do dokumentace nezahrnul, protože do nich nikomu nic není. (Kdybychom však chtěli vytvářet dokumentaci pro interní potřebu,
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 35 z 41
2.18. Dokumentace
Strana 36 z 41
mohli bychom program požádat, aby do dokumentace zahrnul vše, včetně soukromých atributů a metod.) Budete-li se chtít podívat, jak by tato část vypadala, zkuste u nějakého atributu smazat modifikátor private a nechte vytvořit dokumentaci znovu. Čtvrtá část obsahuje přehled definovaných konstruktorů. Všimněte si, že do tabulky je opsána hlavička (modifikátor public se vynechává) a z dokumentačního komentáře je do tabulky převzata vždy první věta (přesněji část textu k první tečce). Počítejte s tím proto ve svých příštích komentářích a pokuste se shrnout všechny důležité informace v první větě. Pátou část tvoří tabulka definovaných metod seřazených abecedně. V levém sloupci je vždy uveden typ návratové hodnoty a případné modifikátory (public se opět vynechává), v pravé části je stejně jako u konstruktorů opsán zbytek hlavičky a první věta dokumentace. Za tabulkou definovaných metod následuje tabulka se seznamem metod, které třída zdědila od svých předků. K této části se ještě vrátíme, až si budeme povídat o dědičnosti. Sedmá část se podrobně věnuje jednotlivým nesoukromým atributům. Protože v naší třídě takové nejsou, bude v dokumentaci opět vynechána. (Odstraníte-li před vytvořením dokumentace u atributů modifikátor private, atributy se zde objeví. Protože jsme k nim ale žádné dokumentační komentáře nenapsali, najdete zde pouze jejich modifikátory, typ a název. Osmá část se podrobně věnuje konstruktorům. U každého konstruktoru je zde opsána celá hlavička a celý dokumentační komentář. Má-li konstruktor parametry a byl-li k nim vytvořen patřičný komentář za značkou @param, objeví se v sekci nadepsané Parameters:. Poslední devátá část se podrobně věnuje definovaným metodám. Stejně jako u konstruktoru je zde u každé metody opsána její hlavička následovaná kompletním dokumentačním komentářem. U funkcí s parametry zde naleznete speciální sekci nadepsanou Parameters: do níž jsou opsány komentáře zapsané za značkou @param, u funkcí vracejících nějakou hodnotu sekci nadepsanou Returns:, do níž se opíše komentář zadaný za značkou @return. Jednotlivé části dokumentace jsou spolu provázané hypertextovými odkazy. Klepnete-li v tabulce atributů, konstruktorů nebo metod na název vybraného objektu, přesunete se automaticky do sekce, kde si můžete přečíst jeho podrobnou dokumentaci. To však stále ještě není všechno. BlueJ je schopen za vás vytvořit dokumentaci nejenom k jednotlivým třídám, ale i k celému projektu. Vytvoří ji navíc tak, abyste ji mohli samostatně prohlížet v nějakém webovém prohlížeči, aniž byste museli příště otevírat BlueJ. Postup je jednoduchý. Vraťte se do aplikačního okna projektu a zadejte příkaz Nástroje → Dokumentace projektu:
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 36 z 41
2.18. Dokumentace
Strana 37 z 41
Obrázek 2.16: Příkaz k vytvoření dokumentace projektu
Tímto příkazem žádáte BlueJ, aby vytvořil dokumentaci ke všem třídám zahrnutým v projektu. BlueJ vytvoří sadu html stránek, které umístí v podsložce doc a otevře hlavní stránku této sady uloženou v souboru index.html. Tato stránka je rozdělena na dvě části: v levé najdete seznam definovaných tříd a v pravé se objeví dokumentace té třídy, na kterou v levém části klepnete. Zároveň vám v horní části nabízí několik dalších užitečných odkazů, z nichž prozatím využijete pouze Index (nebudu jej popisovat, vyzkoušejte si jej).
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 37 z 41
2.19. Shrnutí – co jsme se v kapitole naučili
Strana 38 z 41
Obrázek 2.17: Dokumentace celého projektu
Uložíte-li si tuto stránku mezi své oblíbené webové stránky, budete ji moci otevřít kdykoliv si vzpomenete nezávisle na tom, máte-li zrovna otevřené BlueJ či nikoliv.
2.19 Shrnutí – co jsme se v kapitole naučili Nová třída se vytvoří klepnutím na tlačítko Nová třída a zadáním názvu třídy v následně otevřeném dialogovém okně. Velbloudí notací označujeme způsob zápisu, při němž se několikaslovný název píše bez mezer jako jedno slovo přičemž každé slovo názvu začíná velkým písmenem a ostatní písmena jsou malá – např. StrčPrtstSkrzKrk. Názvy tříd píšeme velbloudí notací s prvním písmenem velkým. Názvy atributů, proměnných a metod píšeme velbloudí notací s prvním písmenem malým. Zdrojový kód třídy je uložen v souboru, který má stejný název jako třída (musí se dodržet i velikost písmen) má příponu .java. Jazyk Java používá dva druhy komentářů: obecný, který je ohraničen komentářovými závorkami /* a */, a řádkový, který začíná znaky // a končí spolu koncem řádku. Komentář můžeme napsat kdekoliv, kde můžeme napsat mezeru. J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 38 z 41
2.19. Shrnutí – co jsme se v kapitole naučili
Strana 39 z 41
Obecný komentář začínající znaky /** je chápána jako dokumentační. Zapisují se do něj informace užitečné pro budoucí uživatele dané třídy, metody, konstanty… Dokumentační komentáře musíme napsat těsně před dokumentovanou konstrukci (třídu, atribut, metodu). Dokumentační komentáře mohou vedle prostého textu obsahovat i HTML značky (tagy). Java zavádí několik speciálních značek začínajících znakem „@“, které slouží k lepšímu popisu některých rysů dokumentovaných konstrukcí, např. parametrů či návratových hodnot dokumentovaných metod. Novou třídu vytvoříme stiskem tlačítka Nová třída a vyplněním následně otevřeného dialogového okna. Třídu odstraníme zadáním příkazu Odstranit v místní nabídce třídy. Definice třídy sestává z hlavičky a těla. Hlavička obsahuje modifikátory blíže specifikující vlastnosti třídy (prozatím známe jen modifikátor public), klíčové slovo class a název třídy. Tělo následuje za hlavičkou, je uzavřeno ve složených závorkách a obsahuje definice všech atributů a metod dané třídy. Po každé úpravě se musí třída před svým prvním spuštěním přeložit. Objeví-li překladač při překladu nějakou chybu, oznámí nám to ve spodním, informačním poli okna editoru. Není-li nám význam chyby zřejmý, můžeme požádat o nápovědu stiskem tlačítka s otazníkem na pravém kraji informačního pole. Definice konstruktoru sestává z hlavičky a těla. Hlavička obsahuje modifikátory následované názvem konstruktoru, který je shodný s názvem třídy, a seznamem parametrů uzavřený v kulatých závorkách. Má-li být konstruktor viditelný zvenku třídy, označíme jej modifikátorem public. Nemá-li konstruktor žádné parametry, budou závorky za jeho názvem prázdné. Parametr deklarujeme tak, že uvedeme jeho typ (u objektových parametrů uvedeme třídu, na jejíž instanci odkazují) následovaný jeho názvem (identifikátorem), prostřednictvím nějž se k němu budeme v těle konstruktoru obracet. Je-li pro nás výhodné zavolat v konstruktoru jiný konstruktor téže třídy, zavoláme jej tak, že napíšeme klíčové slovo this následované seznamem parametrů. Volání konstruktoru this musí být úplně prvním příkazem těl konstruktoru – před ním smějí být již pouze mezery a komentáře. Pro přesný zápis pravidel, podle nichž se vytváří (zapisuje) vysvětlovaná konstrukce, používáme syntaktické definice. Atributy definujeme v těle třídy, avšak mimo těla jejich metod.
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 39 z 41
2.19. Shrnutí – co jsme se v kapitole naučili
Strana 40 z 41
Definice atributů sestává se seznamu modifikátorů následovaného typem definovaného atributu a jeho identifikátorem (názvem) a případným přiřazením počáteční hodnoty. Atributy s výjimkou konstant, které není možné změnit, označujeme modifikátorem private. U tříd rozeznáváme jejich rozhraní, tj. to, co o sobě třída zveřejní a na co se mohou její uživatelé spolehnout, a implementaci, tj. to, jak třída zařídí, že umí to, co vyhlásila v rozhraní. Implementační detaily bychom měli před okolím skrývat, aby nebylo možno funkčnost třídy a jejích instancí ohrozit. Definice metody sestává z hlavičky a těla. Hlavička obsahuje modifikátory následované typem návratové hodnoty, názvem metody a seznamem parametrů uzavřeným v kulatých závorkách. Metody, které nic nevrací, mají jako typ návratové hodnoty uveden typ void. Použité metody a atributy musíme vždy kvalifikovat, tj. napsat před ně název odkazu na instanci (u atributů a metod třídy můžeme použít název třídy), o jejíž metodu nebo atribut se jedná. Kvalifikaci můžeme vynechat pouze v případě, kdy se na danou metodu či atribut obracíme v metodě instance (třídy), na jejíž metodu či atribut se obracíme. Chceme-li zdůraznit, že se obracíme na atribut či metodu té instance, jejíž metodu právě definujeme, kvalifikujeme ji klíčovým slovem this. V případě potřeby můžeme uvnitř metody definovat lokální proměnné. Definice musí obsahovat typ proměnné (u objektových typů třídu instance, na níž bude proměnná odkazovat), identifikátor (název) a případně i přiřazení počáteční hodnoty. Lokální proměnnou nelze použít, dokud se jí nepřiřadí nějaká hodnota. Po ukončení metody jsou všechny její lokální proměnné ztraceny. Potřebuje-li si metoda něco pamatovat mezi svými spuštěními, musí si to uložit do nějakého atributu. Atributy a metody třídy definujeme tak, že mezi jejich modifikátory uvedeme klíčové slovo static. Atributy a metody třídy bývají často označovány jako statické. Má-li být hodnota atributu neměnná (konstantní), uvedeme mezi jeho modifikátory klíčové slovo final. Statickým konstantám je třeba přiřadit jejich hodnotu již v deklaraci, nestatickým konstantám je možno přiřadit počáteční hodnotu v konstruktoru. Jako veřejné mohou být deklarovány pouze konstanty číselných typů. logické konstanty a konstanty typu String. Metody mohou mít i parametry objektových typů. Při zadávání takovýchto parametrů v prostředí BlueJ můžeme využít možnosti zadat takovýto parametr klepnutím na příslušný odkaz v zásobníku odkazů.
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 40 z 41
2.19. Shrnutí – co jsme se v kapitole naučili
Strana 41 z 41
V okně editoru můžeme zadat, zda má editor zobrazit implementaci dané třídy (zdrojový kód) nebo její rozhraní (dokumentaci). Dokumentace je generována automaticky z dokumentačních komentářů. Zadáním příkazu Nástroje → Dokumentace projektu v okně projektu požádáme o vygenerování dokumentace všech tříd v projektu. Tyto dokumentaci si pak můžeme prohlížet HTML prohlížečem nezávisle na spuštění BlueJ.
Autor pracuje jako EDU expert ve firmě Amaio Technologies, Inc.
J02 Vytváříme vlastní třídu.doc, verze 1.10.005, uloženo: středa 14.května.2003 – 15:54
Strana 41 z 41