36
 A k ste sledovali C++ pod lupou, nový seriál bude písaný rovnakým štýlom, azda len s tým rozdielom, e kým pri opise C++ som sa snail obmedzi výklad na štandardné a implementaène nezá- vislé èrty, pri Jave je takýto postup zbytoèný. Jej špecifi- kácia a vývoj je pod taktovkou jedinej firmy (hm, eby monopol?) a kadá implementácia Javy, ktorá nesúhlasí so špecifikáciou, je chybná. Okrem toho vdy je k dispo- zícii takpovediac referenèná implementácia Java platfor- my s názvom Java Runtime Environment, pochádzajúca priamo od tvorcov Javy, f irmy Sun Microsystems, ktorá je k dispozícii zadarmo. Seriál sa bude zaobera Javou ako celkom, teda opisom jednak jazyka, jednak kninice tried, ktoré sú k dispozícii. Príklady, ktoré nájdete v jednotlivých èastiach seriálu, nebudú obmedzené na konkrétne vývojové prostredie. Väèšina komerèných vývojových prostredí je zaloená na  Java Development Kite od firmy Sun Microsystems (na vo¾né stiahnutie v poslednej verzii 1.3 na adrese http://java.sun.com/j2se/1.3 ). Ak nevlastníte licenciu na nijaké komerèné prostredie (ako Borland JBuilder, IBM Visual Age for Java a pod.), JDK na preklad a spúšanie programov úplne postaèuje. Azda len tie komerèné pro- stredia sú výrazne komfortnejšie. Ale ani v prípade, e máte prístup iba k JDK, nemusíte zúfa – na internete je k dispozícii nieko¾ko pomerne šikovných nadstavieb. Pre  jednotnos budem ïalej mlèky predpoklada, e po- uívate JDK. V prípade, e pocítite potrebu doplni si informácie z iných zdrojov , najlepšie bude zaèa na oficiálnych stránkach (na adrese http://java.sun.com/docs). Okrem tohto oficiálneho zdroja existuje nespoèetné mnostvo ïalších stránok a diskusných skupín, ktoré sa venujú  Jave. Takisto sa ete obráti aj na tlaèenú literatúru, tá však podlieha èasu a knihy prekladané z anglických èi iných originálov môu by v èase vydania u mierne zastarané. Ak máte k dispozícii kreditnú kartu, obráte sa priamo na niektorý zo zahranièných internetových ob- chodov – tak sa dajú zohna aj najnovšie knihy s aktuál- nymi informáciami. Cena bude vyššia, ale ijeme v infor- maènej spoloènosti a treba si zvyka, e informácie sú najdrahším obchodným artiklom. Základné pojmy Skôr ne sa pustíme do Javy, bude vhodné ozrejmi si nie- ko¾ko základných pojmov, s ktorými sa v tomto seriáli stretnete. Základnou jednotkou informácie je bit. Premenná s ve¾kosou jedného bitu (takisto logická alebo boolovská premenná) môe nadobúda dva stavy: 0 a 1, resp. false a true. Postupnos ôsmich bitov sa nazýva bajt. Historicky  je bajt najmenšou adresovate¾nou jednotkou poèítaèov ej pamäte. Premenná s ve¾kosou jeden bajt môe nadobú- da 2 8 rôznych hodnôt. Pouívané násobky bajtov vychá- dzajú z binárnej sústavy: 1 kilobajt (1 KB) = 2 10 bajtov, 1 megabajt (1 MB) = 2 20 bajtov atï. Premenné v poèítaèo- vých jazykoch mávajú ïalej šírku 16 bitov (slovo), 32 bitov ( dvojslovo), 64 bitov (štvorslovo). Ich rozsahy sú po rade 2 16 , 2 32 a 2 64 rôznych hodnôt. Pamä poèítaèa je postupnos pamäových buniek s rozsahom jedného bajtu. V moderných operaèných systé- moch musíme rozlišova  fyzickú pamä , ktorá je úplne pod správou operaèného systému a programy ju obyèaj- ne neadresujú priamo, a virtuálnu pamä, ktorú si eme predstavi ako nezávislý pamäový priestor, pri- delený kadému procesu, rozdelený na jednotlivé strán- ky. Z nich sa vo fyzickej pamäti nachádzajú len tie, ktoré proces práve pouíva, ostatné sú odloené na disku v stránkovacom súbore. Koncept virtuálnej pamäte umoòuje programom vyuíva podstatne väèšiu pamä, ako je fyzicky k dispozícii. Štandardný vstup a štandardný výstup sú pojmy pochádzajúce z operaèného systému UNIX. Stretneme sa s nimi aj v Jave – ide o štandardné rozhrania na vstup údajov do programu a na výstup údajov z programu. Štandardný vstup je implicitne prepojený s klávesnicou, štandardný výstup smeruje na obrazovku. Obe rozhrania  je mopomocou prostriedkov operaèného systému presmerova napríklad na súbory. ¼ahký úvod do OOP Základné pojmy sme si objasnili, všetko ostatné sa dozviete v samotnom seriáli – s jedinou výnimkou, kto- rou sú princípy objektovo orientovaného programovania. Neodporúèam štúdium Javy bez minimálne základných znalostí OOP, preto si tu uvedieme aspoò f undamentálne princípy. V kadom prípade, kto nemá v tejto oblasti  jasno, mal by si vedomosti èo najskôr doplni. Paradigma OOP je zaloená na modelovaní objektov reálneho sveta. Objekt je v OOP základnou entitou. Charakterizovaný je svojím stavom (urèeným hodnotou tzv. atribútov objektu) a svojím správaním, ktoré definu-  je, èo objekt dokáe robi. Stav objektu je navonok nevi- dite¾ný – nevieme, èo ho tvorí ani ako je uloený. Toto je prvý základný princíp OOP, hovorí sa mu zapuzdrenie (encapsulation). Dôvodom ukrytia stavu objektu pred oko- lím je snaha zabráni takým jeho modifikáciám, ktoré by uviedli objekt do nekonzistent ného stavu. Interakcia medzi objektmi sa realizuje pomocou posie- lania správ. Kadý objekt dáva k dispozícii zoznam správ, na ktoré dokáe reagova (to je to spomínané správanie objektu). Napríklad v bankovej aplikácii by mohol objekt Úèet reagova na správy „Vypoèítaj úrok“, „Preveï sumu“ a podobne. Dôleité je, e iniciátor správy sa nemusí stara o to, akým spôsobom príjemca jeho správu spra- cuje. Príjemca sa, naopak, nestará o to, kto mu správu poslal. V súvislosti so zapuzdrením je zrejmá zjavná výhoda OOP oproti klasickému štýlu: pokia¾ je stav objek- tu pred svetom ukrytý a prístupné je iba komunikaèné rozhranie, môeme kedyko¾vek objekt vymeni za iný s rovnakým rozhraním. Pokia¾ sa nezmení funkènos objektu, okolité objekty nemusia ani len tuši, e k neja- kej výmene došlo. Druhým dôleitým konceptom OOP je  polymorfizmus. Táto vlastnos znamená, e viacero objektov dokáe rea- gova na jednu a tú istú správu, kadý však inak, svojím vlastným spôsobom. Klasickým prípadom môe by sprá- va „Serializuj sa“. Serializácia objektu je zakódovanie  jeho stavu pre uloenie napríklad do súboru, z ktorého bude v budúcnosti moné objekt rekonštruova. Je zrej- mé, e kadý objekt sa bude serializova inak; to nás však nemusí zaujíma, staèí, keï pošleme príslušnú správu všetkým objektom. Zapuzdrenie a polymorfizmus sú naozaj základnými princípmi OOP. Bez nich by celá koncepcia stratila zmy- sel. Èasto sa však môete stretnú ešte s pojmami trieda a dediènos. Triedy sú v klasickom OOP šablónami, na základe ktorých je moné generova nové objekty. Dôleité je, e sú to takisto objekty (lepšie povedané metaobjekty). V mnohých jazykoch (napríklad v C++, ale Java nie je výnimkou) však nie je moné vytvori objekt bez toho, aby sme najprv definovali jeho triedu. V takýchto jazykoch sú triedy iba jazykovými konš trukci- ami. Posledný pojem – dediènos – predstavuje monos usporadúva objekty, resp. ich triedy do hierarchických úrovní na základe vzahu generalizácie/špecializácie. Napríklad objekt TermínovanýÚèet je špeciálnym prípa- dom objektu Úèet, èo môeme s úspechom vyui a v definícii objektu TermínovanýÚèet uvies len odlišnosti oproti generickému Úètu.  Java je zameraná takmer výhradne objektovo. V nie- ktorých oblastiach zachádza viac do håbky ako C++, hoci stále to nie je taký silne objektový jazyk ako napríklad Smalltalk. Ostatne, o všetkom sa budete ma monos presvedèi pri sledovaní tohto seriálu.  Java: nová paradigma Na zaèiatok si polome otázku, èo vlastne Java je. Odpoveï nie je triviálna. Java toti nie je len ïalší z dlhého radu programovacích jazykov, hoci moderný a efektívny, ani módna záleitos, vyvolaná masívnou pro- pagáciou materskej firmy Sun Microsystems, ktorej diví- zia JavaSoft má vývoj Javy na starosti, a u vôbec nie zábavná technológia na vytváranie appletov s poskakujú- cim textom, oivujúcim a donedávna statické webové stránky. Nie, Java je komplexná platforma pre vývoj a beh širokého spektra aplikácií v heterogénnom sieovom pro- stredí. História Javy je pomerne krátka. Zaèiatkom 90. rokov zatia¾ ešte tohto storoèia skupina výskumných pracovní- kov vo firme Sun Microsystems pracovala na projekte vývoja univerzálneho softvéru slúiaceho na riadenie a programovanie sie ových zariadení a tzv. vno rených systémov (embedded systems), ako napr. èipy v mikro- vlnkách, mobilných telefónoch, spotrebnej elektronike a pod. Výskumníc i pôvodne rátali s pouit ím programo- vacieho jazyka C++, èoskoro však usúdili, e tento jazyk  je na ich úèely príliš zloitý, nej ednoznaèný a nesp o¾ahli- vý. Krátko nato uzrel svetlo sveta ich vlastný produkt, nazvaný jednoducho Oak. Tvrdí sa, e jeho názov má na svedomí dub, ktorý rástol pred oknami pracovne vedúce- ho projektu Jamesa Goslinga. Celý projekt tak trochu predbehol svoju dobu a zrejme by upadol do zabudnutia, neby razantného nástupu internetu v roku 1995. Vtedy pán Gosling vycítil, e jeho  jazyk je ideálny na pouitie v heterogénnyc h sieových prostrediach, ako je aj internet. Spolu s výskumnou sku- pinou pripravili koncept univerzálnej programovacej platformy, orientovanej na sieové prostredie a nezávis- lej od pouitého hardvéru èi operaèného systému. Platforma a programovací jazyk dostali názov Java, pod¾a  jednej z historiek vraj preto, lebo ¾udia, ktorí majú Javu „na svedomí“, s ob¾ubou pijú kávu (java je americký slan- gový výraz pre kávu). Prvá verzia Javy s oznaèením 1.0 obsahovala kninicu tried pozostávajúcu zo siedmich základných balíkov, ktoré pokrývali najdôleitejšie oblasti pouitia, ako práca s reazcami, matematické funkcie, sieové funkcie, práca s grafikou a pod. K jej rozšíreniu prispela jednak jej vo¾ná licencia – vývojové prostredie na tvorbu javovských apli- kácií Java Development Kit bolo k dispozícii zadarmo –,  jednak vytvorenie webového prehliadaèa HotJava, ktorý ako prvý umoòoval prehliadanie stránok s vloenými mikroaplikáciami, tzv. appletmi (mimochodom, celý bol napísaný v Jave). Applety poskytovali nevídanú mieru interaktivity na dovtedy statických webových stránkach, a preto neèudo, e podporu technológie Java v rýchlom slede ohlásili aj výrobcovia dvoch najznámejších webo- vých prehliadaèov, spoloènosti Netscape a Microsoft. U v roku 1997 firma Sun uvo¾nila ïalšiu verziu Javy s oznaè ením Jav a 1.1. V špecif ikácii ja zyka došl o k nieko¾kým drobným, ale uitoèným zmenám, najväèšie rozšírenie však podstúpila kninica tried. Poèet balíkov PC REVUE 1 JAVA POD LUPOU Java pod lupou

Java SK

Embed Size (px)

Citation preview

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 1/36

 Ak ste sledovali C++ pod lupou, nový seriálbude písaný rovnakým štýlom, azda len s tým

rozdielom, e kým pri opise C++ som sa snailobmedzi výklad na štandardné a implementaène nezá-vislé èrty, pri Jave je takýto postup zbytoèný. Jej špecifi-kácia a vývoj je pod taktovkou jedinej firmy (hm, ebymonopol?) a kadá implementácia Javy, ktorá nesúhlasíso špecifikáciou, je chybná. Okrem toho vdy je k dispo-zícii takpovediac referenèná implementácia Java platfor-my s názvom Java Runtime Environment, pochádzajúcapriamo od tvorcov Javy, f irmy Sun Microsystems, ktorá jek dispozícii zadarmo. Seriál sa bude zaobera Javou akocelkom, teda opisom jednak jazyka, jednak kninice tried,ktoré sú k dispozícii.

Príklady, ktoré nájdete v jednotlivých èastiach seriálu,nebudú obmedzené na konkrétne vývojové prostredie.Väèšina komerèných vývojových prostredí je zaloená na

 Java Development Kite od firmy Sun Microsystems (navo¾né stiahnutie v poslednej verzii 1.3 na adresehttp://java.sun.com/j2se/1.3). Ak nevlastníte licenciu nanijaké komerèné prostredie (ako Borland JBuilder, IBMVisual Age for Java a pod.), JDK na preklad a spúšanieprogramov úplne postaèuje. Azda len tie komerèné pro-stredia sú výrazne komfortnejšie. Ale ani v prípade, emáte prístup iba k JDK, nemusíte zúfa – na internete jek dispozícii nieko¾ko pomerne šikovných nadstavieb. Pre jednotnos budem ïalej mlèky predpoklada, e po-uívate JDK.

V prípade, e pocítite potrebu doplni si informáciez iných zdrojov, najlepšie bude zaèa na oficiálnychstránkach (na adrese http://java.sun.com/docs). Okremtohto oficiálneho zdroja existuje nespoèetné mnostvo

ïalších stránok a diskusných skupín, ktoré sa venujú Jave. Takisto sa môete obráti aj na tlaèenú literatúru, távšak podlieha èasu a knihy prekladané z anglických èiiných originálov môu by v èase vydania u miernezastarané. Ak máte k dispozícii kreditnú kartu, obráte sapriamo na niektorý zo zahranièných internetových ob-chodov – tak sa dajú zohna aj najnovšie knihy s aktuál-nymi informáciami. Cena bude vyššia, ale ijeme v infor-maènej spoloènosti a treba si zvyka, e informácie súnajdrahším obchodným artiklom.

Základné pojmySkôr ne sa pustíme do Javy, bude vhodné ozrejmi si nie-ko¾ko základných pojmov, s ktorými sa v tomto seriálistretnete.

Základnou jednotkou informácie je bit. Premenná sve¾kosou jedného bitu (takisto logická alebo boolovskápremenná) môe nadobúda dva stavy: 0 a 1, resp. false atrue. Postupnos ôsmich bitov sa nazýva bajt. Historicky je bajt najmenšou adresovate¾nou jednotkou poèítaèovejpamäte. Premenná s ve¾kosou jeden bajt môe nadobú-da 28 rôznych hodnôt. Pouívané násobky bajtov vychá-dzajú z binárnej sústavy: 1 kilobajt (1 KB) = 210 bajtov, 1megabajt (1 MB) = 220 bajtov atï. Premenné v poèítaèo-vých jazykoch mávajú ïalej šírku 16 bitov (slovo), 32bitov (dvojslovo), 64 bitov (štvorslovo). Ich rozsahy sú porade 216, 232 a 264 rôznych hodnôt.

Pamä  poèítaèa je postupnos pamäových buniek srozsahom jedného bajtu. V moderných operaèných systé-moch musíme rozlišova  fyzickú pamä , ktorá je úplne

pod správou operaèného systému a programy ju obyèaj-ne neadresujú priamo, a virtuálnu pamä, ktorú simôeme predstavi ako nezávislý pamäový priestor, pri-delený kadému procesu, rozdelený na jednotlivé strán-ky. Z nich sa vo fyzickej pamäti nachádzajú len tie, ktoréproces práve pouíva, ostatné sú odloené na disku v

stránkovacom súbore. Koncept virtuálnej pamäteumoòuje programom vyuíva podstatne väèšiu pamä,

ako je fyzicky k dispozícii.Štandardný vstup a štandardný výstup sú pojmypochádzajúce z operaèného systému UNIX. Stretneme sas nimi aj v Jave – ide o štandardné rozhrania na vstupúdajov do programu a na výstup údajov z programu.Štandardný vstup je implicitne prepojený s klávesnicou,štandardný výstup smeruje na obrazovku. Obe rozhrania je moné pomocou prostriedkov operaèného systémupresmerova napríklad na súbory.

¼ahký úvod do OOPZákladné pojmy sme si objasnili, všetko ostatné sadozviete v samotnom seriáli – s jedinou výnimkou, kto-rou sú princípy objektovo orientovaného programovania.Neodporúèam štúdium Javy bez minimálne základných

znalostí OOP, preto si tu uvedieme aspoò fundamentálneprincípy. V kadom prípade, kto nemá v tejto oblasti jasno, mal by si vedomosti èo najskôr doplni.

Paradigma OOP je zaloená na modelovaní objektovreálneho sveta. Objekt je v OOP základnou entitou.Charakterizovaný je svojím stavom (urèeným hodnotoutzv. atribútov objektu) a svojím správaním, ktoré definu- je, èo objekt dokáe robi. Stav objektu je navonok nevi-dite¾ný – nevieme, èo ho tvorí ani ako je uloený. Toto jeprvý základný princíp OOP, hovorí sa mu zapuzdrenie(encapsulation). Dôvodom ukrytia stavu objektu pred oko-lím je snaha zabráni takým jeho modifikáciám, ktoré byuviedli objekt do nekonzistentného stavu.

Interakcia medzi objektmi sa realizuje pomocou posie-lania správ. Kadý objekt dáva k dispozícii zoznam správ,

na ktoré dokáe reagova (to je to spomínané správanieobjektu). Napríklad v bankovej aplikácii by mohol objektÚèet reagova na správy „Vypoèítaj úrok“, „Preveï sumu“a podobne. Dôleité je, e iniciátor správy sa nemusístara o to, akým spôsobom príjemca jeho správu spra-cuje. Príjemca sa, naopak, nestará o to, kto mu správuposlal. V súvislosti so zapuzdrením je zrejmá zjavnávýhoda OOP oproti klasickému štýlu: pokia¾ je stav objek-tu pred svetom ukrytý a prístupné je iba komunikaènérozhranie, môeme kedyko¾vek objekt vymeni za inýs rovnakým rozhraním. Pokia¾ sa nezmení funkènosobjektu, okolité objekty nemusia ani len tuši, e k neja-kej výmene došlo.

Druhým dôleitým konceptom OOP je  polymorfizmus.Táto vlastnos znamená, e viacero objektov dokáe rea-

gova na jednu a tú istú správu, kadý však inak, svojímvlastným spôsobom. Klasickým prípadom môe by sprá-va „Serializuj sa“. Serializácia objektu je zakódovanie jeho stavu pre uloenie napríklad do súboru, z ktoréhobude v budúcnosti moné objekt rekonštruova. Je zrej-mé, e kadý objekt sa bude serializova inak; to nás všaknemusí zaujíma, staèí, keï pošleme príslušnú správuvšetkým objektom.

Zapuzdrenie a polymorfizmus sú naozaj základnýmiprincípmi OOP. Bez nich by celá koncepcia stratila zmy-sel. Èasto sa však môete stretnú ešte s pojmami triedaa dediènos. Triedy sú v klasickom OOP šablónami, nazáklade ktorých je moné generova nové objekty.Dôleité je, e sú to takisto objekty (lepšie povedanémetaobjekty). V mnohých jazykoch (napríklad v C++,

ale Java nie je výnimkou) však nie je moné vytvoriobjekt bez toho, aby sme najprv definovali jeho triedu.V takýchto jazykoch sú triedy iba jazykovými konštrukci-ami.

Posledný pojem – dediènos – predstavuje monosusporadúva objekty, resp. ich triedy do hierarchických

úrovní na základe vzahu generalizácie/špecializácie.Napríklad objekt TermínovanýÚèet je špeciálnym prípa-

dom objektu Úèet, èo môeme s úspechom vyui a vdefinícii objektu TermínovanýÚèet uvies len odlišnostioproti generickému Úètu.

 Java je zameraná takmer výhradne objektovo. V nie-ktorých oblastiach zachádza viac do håbky ako C++, hocistále to nie je taký silne objektový jazyk ako napríkladSmalltalk. Ostatne, o všetkom sa budete ma monospresvedèi pri sledovaní tohto seriálu.

 Java: nová paradigmaNa zaèiatok si polome otázku, èo vlastne Java je.Odpoveï nie je triviálna. Java toti nie je len ïalší zdlhého radu programovacích jazykov, hoci moderný aefektívny, ani módna záleitos, vyvolaná masívnou pro-pagáciou materskej firmy Sun Microsystems, ktorej diví-

zia JavaSoft má vývoj Javy na starosti, a u vôbec niezábavná technológia na vytváranie appletov s poskakujú-cim textom, oivujúcim a donedávna statické webovéstránky. Nie, Java je komplexná platforma pre vývoj a behširokého spektra aplikácií v heterogénnom sieovom pro-stredí.

História Javy je pomerne krátka. Zaèiatkom 90. rokovzatia¾ ešte tohto storoèia skupina výskumných pracovní-kov vo firme Sun Microsystems pracovala na projektevývoja univerzálneho softvéru slúiaceho na riadeniea programovanie sieových zariadení a tzv. vnorenýchsystémov (embedded systems), ako napr. èipy v mikro-vlnkách, mobilných telefónoch, spotrebnej elektronikea pod. Výskumníci pôvodne rátali s pouitím programo-vacieho jazyka C++, èoskoro však usúdili, e tento jazyk

 je na ich úèely príliš zloitý, nejednoznaèný a nespo¾ahli-vý. Krátko nato uzrel svetlo sveta ich vlastný produkt,nazvaný jednoducho Oak. Tvrdí sa, e jeho názov má nasvedomí dub, ktorý rástol pred oknami pracovne vedúce-ho projektu Jamesa Goslinga.

Celý projekt tak trochu predbehol svoju dobu a zrejmeby upadol do zabudnutia, neby razantného nástupuinternetu v roku 1995. Vtedy pán Gosling vycítil, e jeho jazyk je ideálny na pouitie v heterogénnych sieovýchprostrediach, ako je aj internet. Spolu s výskumnou sku-pinou pripravili koncept univerzálnej programovacejplatformy, orientovanej na sieové prostredie a nezávis-lej od pouitého hardvéru èi operaèného systému.Platforma a programovací jazyk dostali názov Java, pod¾a jednej z historiek vraj preto, lebo ¾udia, ktorí majú Javu

„na svedomí“, s ob¾ubou pijú kávu (java je americký slan-gový výraz pre kávu).

Prvá verzia Javy s oznaèením 1.0 obsahovala kninicutried pozostávajúcu zo siedmich základných balíkov,ktoré pokrývali najdôleitejšie oblasti pouitia, ako prácas reazcami, matematické funkcie, sieové funkcie, prácas grafikou a pod. K jej rozšíreniu prispela jednak jej vo¾nálicencia – vývojové prostredie na tvorbu javovských apli-kácií Java Development Kit bolo k dispozícii zadarmo –, jednak vytvorenie webového prehliadaèa HotJava, ktorýako prvý umoòoval prehliadanie stránok s vloenýmimikroaplikáciami, tzv. appletmi (mimochodom, celý bolnapísaný v Jave). Applety poskytovali nevídanú mieruinteraktivity na dovtedy statických webových stránkach,a preto neèudo, e podporu technológie Java v rýchlom

slede ohlásili aj výrobcovia dvoch najznámejších webo-vých prehliadaèov, spoloènosti Netscape a Microsoft.

U v roku 1997 firma Sun uvo¾nila ïalšiu verziu Javys oznaèením Java 1.1. V špecifikácii jazyka došlo knieko¾kým drobným, ale uitoèným zmenám, najväèšierozšírenie však podstúpila kninica tried. Poèet balíkov

PC REVUE 1

JAVA POD LUPOU

Java pod lupou

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 2/36

sa rozšíril zo siedmich na dvadsadva – pribudla lepšiapodpora grafiky, monos práce s komprimovanýmisúbormi, s databázami, bezpeènostné funkcie, podporadistribuovaných aplikácií a predovšetkým koncept tzv. Java Beans (zapuzdrené komponenty, nieèo ako ActiveX).

Vývoj Javy sa však nezastavil. V priebehu poslednýchrokov poèiatoèné nadšenie zo strany tvorcov webovýchstránok, ktoré sa prakticky prejavovalo tým, e na javov-ský applet ste narazili pomaly na kadej druhej stránke,

našastie opadlo a Java sa postupne pretransformovalana reálne pouite¾nú technológiu. Najnovšia verzia Javys marketingovým oznaèením Java 2 Platform predstavujeskutoène komplexnú programovaciu platformu, mimo-riadne vhodnú na nasadenie v heterogénnych podniko-vých aplikáciách a intranetoch, umoòujúcu úplnúsieovú interoperabilitu a beh distribuovaných aplikáciípod¾a súèasných štandardov.

Platformu Java 2 firma Sun pomyselne delí do trochvetiev: Java 2 Standard Edition, Java 2 Enterprise Editiona Java 2 Micro Edition. V seriáli Java pod lupou sa bude-me zaobera prvou vetvou, J2SE, ktorá predstavuje plno-hodnotnú platformu pre vývoj desktopových aplikácií,poskytujúcu všetky èrty verzie 1.1 s nieko¾kými podstat-nými zlepšeniami v oblasti pouívate¾ského rozhrania,

práce so zvukom, podpory distribuovaných aplikácií atransakèného spracovania. Druhá vetva, J2EE, zahàòaoproti J2SE technológie urèené na nasadenie v prostredípodnikových aplikácií, ako Enterprise Java Beans, JavaServer Pages a pod. O tejto vetve si azda povieme nieèoviac v budúcnosti. Koneène tretia vetva, J2ME, je urèenápre zariadenia ako vreckové poèítaèe èi mobilné telefóny.

Na stránkach JavaSoftu nájdete okrem týchto trochhlavných vetiev mnostvo špecifikácií ïalších technológiísúvisiacich s Javou, ktoré však tak trochu presahujúrámec nášho seriálu, a preto sa nimi zaobera nebudeme.Kto má o ne záujem, môe si príslušné informácievyh¾ada na internete.

Charakteristika Javy

V oficiálnom opise The Java Language Environment (náj-dete ho na adrese http://java.sun.com/docs/white/lan-genv) je Java výstine charakterizovaná mnoinou adjek-tív. I keï ich zoznam pôsobí ako zbierka typických mar-ketingových „buzzwords“, prekvapivo dobre vystihujúpodstatné vlastnosti Javy:

 Java je  jednoduchá. Jednou z najväèších nevýhod jazykov ako C++ je ich zloitos. Isto mi dáte za pravdu,e na dokonalé zvládnutie C++ potrebujete ma pomer-ne rozsiahle vedomosti a dostatoène dlhú prax a vašacesta k poznaniu bude dládená neuverite¾nýmmnostvom chýb, ktoré stvoríte. Práve preto bola Java odzaèiatku navrhovaná tak, aby vaša krivka uèenia bolapokia¾ mono èo najstrmšia a aby vás netrafil š¾ak skôr,ne nieèo uitoèné vyprodukujete. Autori jazyka pri návr-hu Javy vychádzali z existujúcich objektovo orientova-ných jazykov (C++, Smalltalk, Objective C, Eiffel a pod.),z ktorých systematicky odstraòovali príliš zloité èrty, adospeli ku koneènému, minimalistickému stavu. Java jeskutoène ukákovým príkladom jednoduchého a pritomdostatoène výkonného jazyka.

 Java sa vám bude zda známa. Neoddiskutovate¾nouprednosou Javy je jej príbuznos s C++ – programv Jave vyzerá na poh¾ad takmer ako program v C++, a akaspoò trochu ovládate C++, nemali by ste ma so zvlád-nutím Javy iadne problémy. Java pouíva podobné úda- jové typy, operátory, jazykové konštrukcie i príkazy. Narozdiel od C++ však oslobodzuje programátora odpamätania si komplikovaných pravidiel, od dodriavaniasprávnych postupov (napr. pri alokácii a uvo¾òovanípamäte), odstraòuje mnohé síce uitoèné, ale prinesprávnom pouití nebezpeèné konštrukcie a predo-všetkým nepozná ukazovatele, èo je zrejme najèastejšiapríèina chýb v programoch C++. Ako niekto priliehavopoznamenal, Java je C++ s menej povrazmi, na ktorýchby sa programátor mohol obesi. Kruté, ale pravdivé.

 Java je objektovo orientovaná. Dnes hádam aninetreba zdôrazòova, e klasický procedurálny a funkcio-nálny spôsob návrhu aplikácie je preitok. Objektovoorientovaná analýza, návrh a programovanie vedú kpreh¾adnejšej štruktúre, lepšej orientácii v programe a kmenšej náchylnosti na výskyt chýb. Samozrejme, OO prí-stup nie je zázraèný prútik, ktorého mávnutím nám podrukami vykvitne perfektná a bezchybná aplikácia. Jehovýhoda je v snahe o napodobenie objektov reálneho

sveta, ich stavu a správania – takýto spôsob tvorby sof-tvéru je nám rozhodne bliší ako úporné, procedurálnenapodobovanie „myslenia“ poèítaèa. Java podporujeprakticky všetky dôleité princípy OO programovania –zapuzdrenie stavu objektov a jeho ukrytie pred von-kajším svetom, komunikáciu medzi objektmi pomocouspráv (ktoré majú za následok vyvolanie príslušnýchmetód objektov), polymorfné správanie objektov, tedarôznu reakciu rôznych objektov na jednu a tú istú sprá-vu, triedy (iba ako jazykové konštrukcie, a nie ako plno-hodnotné runtimeové metaobjekty), jednoduchú dediè-nos (na simuláciu viacnásobnej dediènosti slúia tzv.rozhrania). Podpora OO paradigmy v Jave úzko súvisí s jejorientáciou na sieové prostredia a distribuované apliká-cie.

 Java je architektonicky nezávislá. Pri klasickomspôsobe vývoja aplikácií musí softvérový výrobca vytvo-ri osobitnú verziu aplikácie pre kadú podporovanú plat-formu a neraz aj pre kadý podporovaný operaèný sys-tém. Tento prístup je nesporne èasovo aj finanène nároè-ný, nehovoriac o nutnosti vyrovnáva sa so špecifikami jednotlivých platforiem. Java vám ponúka šalamúnskeriešenie nezávislosti od konkrétneho prostredia: javovsképrogramy nie sú v binárnej forme zloené z natívnychinštrukcií toho-ktorého procesora, ale z inštrukcií tzv.bajt-kódu, platformovo nezávislého inštrukèného súboru.Medzi hardvérom/softvérom príslušnej platformy a prog-ramom v Jave leí vrstva tzv. virtuálneho poèítaèa (JavaVM), ktorý dokáe inštrukcie bajt-kódu interpretova. Javovský program je tak moné spusti na ¾ubovo¾nejplatforme, pre ktorú existuje javovský virtuálny stroj.Softvérovému výrobcovi zo zaèiatku tohto odseku potomstaèí vytvori jedinú verziu aplikácie, ktorú bude monéspusti všade. Pre tento koncept má firma Sun ob¾úbenéheslo: „Write Once, Run Everywhere.“

 Java je portabilná. Mono máte dojem, e portabil-nos Javy je priamym dôsledkom jej architektonickejnezávislosti. Je za tým však ešte nieèo viac: v špecifikáciinapríklad C++ je mnoho vecí definovaných ako imple-mentaène závislé. Nieèo také v Jave nenájdete. Všetkyúdajové typy majú presne stanovený rozsah, všetky jazy-kové konštrukcie sa správajú za kadých okolností rov-nako, nezávisle od konkrétnej implementácie virtuálnehostroja. Okrem toho pôvodný sunovský virtuálny stroj jenapísaný v ANSI C a je maximálne portabilný v zmysleštandardu POSIX.

 Java je robustná a spo¾ahlivá. Oproti jazykom akoC++ má Java ove¾a prísnejšiu syntax, take mnoho poten-ciálnych zdrojov chýb je odstránených u poèas fázy pre-kladu zdrojových textov. Kontrola binárnych triedpokraèuje aj vo fáze behu programu. Klasické linkovanie,ako ho poznáme z iných jazykov, sa deje dynamicky, v oka-mihu, keï je tá-ktorá trieda potrebná. Javovský virtuálnystroj poèas behu kontroluje správnos a konzistentnosnaèítavaných tried, správnos typov parametrov volanýchmetód a podobne. Iným ve¾kým rozdielom Javy oprotiC++ je neporovnate¾ne robustnejšia správa pamäte. V Jave sa nemôe sta, e budete pristupova knejakej oblas-ti pamäte iným ako povoleným spôsobom, okrem toho

uvo¾òovanie nepotrebných objektov z pamäte je automa-tické, èím sa eliminujú klasické memory-leak problémy.  Java je interpretovaná. Bohuia¾, chcelo by sa mi

poveda. V podstate kadý program je poèas behu inter-pretovaný – klasické natívne programy sú však interpre-tované priamo procesorom. Javovské programy vzh¾a-dom na prítomnos vrstvy virtuálneho stroja musia by

interpretované softvérovo. (Objavujú sa síce správy odedikovanom hardvéri, na ktorom bude môc bea prog-ram v Jave priamo, ale zatia¾ sme niè podobné nevideli.)Softvérová interpretácia má však podstatnú nevýhodu – je jednoducho pomalšia. Našastie procesory sú èorazrýchlejšie a virtuálne stroje stále efektívnejšie, take tátonevýhoda Javy sa dá ako-tak strávi.

 Java je dynamická. Ako bolo povedané, pri vývojiaplikácií v Jave sa klasická linkovacia fáza odkladá a do

okamihu, keï je príslušná trieda naozaj potrebná.Kompilátor všetky odkazy na triedy ukladá nie v binár-nom, èíselnom tvare, ale v symbolickom, mennom.Znamená to okrem iného, e pri zmene definície jednejtriedy nie je nevyhnutné opätovne preklada zdrojovésúbory všetkých tých tried, ktoré so zmenenou triedoupracujú. Dokonca je v princípe moné vymeni binárnysúbor s definíciou triedy aj za behu aplikácie, ak táto trie-da dosia¾ nebola naèítaná. Pouívané triedy môu bynaahované z lokálneho systému, ale aj z akéhoko¾vekmiesta dostupného cez sie (presne takto sa správajúapplety vo webových stránkach). Poslednou ve¾kou výho-dou je, e triedy v Jave majú svoju vlastnú run-timereprezentáciu, take je moné za behu programu zisovatyp akéhoko¾vek objektu, dokonca mono vytvori inš-

tanciu triedy, ktorej názov bude známy a poèas behuprogramu.

 Java je bezpeèná. Vzh¾adom na predpokladanépouitie Javy v implicitne nezabezpeèených sieovýchprostrediach pri jej návrhu sa kládol ve¾ký dôraz na bez-peènostné opatrenia znemoòujúce potenciálne zneui-tie existujúceho kódu na iné ako predpokladané úèely.Prvým, pomerne dôleitým predpokladom je samotnýpamäový model Javy. Programátor v zásade nikdy nevie,kde a akým spôsobom sú v pamäti uloené jednotlivé inš-tancie tried a aká je ich vnútorná reprezentácia. Keïev Jave neexistujú ukazovatele, nemáte nijakú monospristupova do ¾ubovo¾nej, explicitne urèenej oblastipamäte. Ïalším ochranným prvkom je mechanizmusnaèítavania tried (tzv. class loader ). Ten zabezpeèí, e nie je moné štandardné triedy, ktoré sa vdy nachádzajú nalokálnom systéme, nahradi podvrhnutými verziami,naèítavanými zo siete. Okrem toho kadá naèítaná triedaprejde dôslednou kontrolou bajt-kódu, ktorá nekorektné,nebezpeèné èi inak neakceptovate¾né triedy jednoduchoodmietne naèíta. Dôleité je, e táto kontrola sa vykoná-va iba raz, pri naèítavaní triedy a poèas behu programusa interpret Javy nemusí zdrova napríklad kontrolouzásobníka, typov operandov a podobne.

 Java podporuje multithreading. Dnes u hádamnetreba vysvet¾ova výhody multithreadingu. Ak vámtoto slovo niè nehovorí, tak ide o monos existencie via-cerých threadov (vykonávacích vlákien) v rámci jednéhoprocesu. Všetky thready zdie¾ajú adresný priestor a pro-striedky materského procesu, len z h¾adiska plánovaèaprocesov vystupujú ako samostatné plánovate¾né entity,to znaèí, e súaia o procesor. Výhoda threadov jenesporná – klasickým príkladom môe by textový proce-sor. V jednom z threadov editujete dokument, druhý mána starosti napríklad prekres¾ovanie obrazovky, ïalšítlaèenie a ešte ïalší sa môe stara napríklad o kontrolupravopisu. Procesor je vyuívaný ove¾a efektívnejšie aprogram vykazuje lepší ohlas. Java je jeden z mála jazy-kov, ktorý zahàòa podporu multithreadingu na úrovni jazyka. Priamo pomocou príslušnej triedy a jej metód jemoné vytvára, spúša i zastavova jednotlivé thready.Tieto thready sú v závislosti od pouitej hardvérovej asoftvérovej platformy úplne preemptívne. V multithrea-dovom prostredí je tie nevyhnutná prítomnos synchro-

nizaèných prostriedkov. Java obsahuje podporu premonitory (vzájomné vyluèovanie pre prístup k triede) apre podmienené premenné (conditional variables).

Prvý programMáme teda vytvorenú predstavu o tom, èo Java je, aké mávlastnosti a ako zhruba funguje. Aby bola prvá èas seriá-

JAVA POD LUPOU

2 PC REVUE

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 3/36PC REVUE 3

JAVA POD LUPOU

lu úplná, ukáeme si ešte na záver azda najjednoduchšíprogram, aký sa v Jave dá napísa. Tradície neradno ruši,preto program vypíše na konzolu obligátny text „Hello,world!“:

public class HelloWorld{

public static void main(String[] args){

System.out.println("Hello, world!");}

}

Program si pravdepodobne budete chcie vyskúša.Prepíšte ho teda do súboru, ktorý musíte pomenovaHelloWorld.java. Preklad spustíte najlepšie v konzolovomokne/DOS boxe zadaním riadka javac HelloWorld.java, po jeho skonèení v aktuálnom adresári pribudne súborHelloWorld.class. To je súbor s binárnym bajt-kódomvytvorenej triedy HelloWorld. Spustíte ho jednoducho –zadaním riadka java HelloWorld (obr. 1). V prípade, epouívate JDK 1.3, je moné, e budete musie do pre-mennej prostredia CLASSPATH prida cestu k aktuálnemuadresáru, èo je znak . (bodka). Neviem síce preèo, v pred-chádzajúcich verziách to nebolo potrebné, ale v operaè-ných systémoch Windows 2000 ani Windows NT (iné somnetestoval) bez tejto úpravy nijaký javovský programnespustíte.

 Poznámka:  V operaèných systémoch Windows 2000/NT sa

 premenné prostredia definujú v Control paneli, v applete

System. V operaèných systémoch Windows Me/9x treba

 prida príslušný riadok do súboru autoexec.bat.)

2. èas  

Na úvod tejto èasti by som rád poznamenal, e je prak-ticky nemoné takú rozsiahlu tému, akou Java a jej špeci-fikácia nepochybne je, opísa a vysvetli lineárne. S tro-chou zjednodušenia sa dá poveda, e v nej všetko sovšetkým súvisí. To vedie k nepríjemnému rozhodovaniumedzi snahou o výklad smerom od absolútnych teoretic-

kých základov k prakticky pouite¾ným informáciám,bohuia¾, aspoò spoèiatku na úkor uitoènosti, a medzipokusmi podáva informácie v podobe komentárovk praktickým príkladom, èo zase pôsobí menej preh¾adnea menej exaktne.

Nový seriál bude inklinova skôr k prvému spôsobuvýkladu, i keï je ve¾mi pravdepodobné, e sa nájde èitate¾,ktorý by radšej volil druhú cestu. K môjmu rozhodnutiu vove¾kej miere prispeli prevane kladné ohlasy na seriálC++ pod lupou, v ktorého štýle by som rád pokraèoval. Jedinou významnejšou výnimkou bude zaèiatok tohtopokraèovania, pretoe na úplnom zaèiatku jednoduchotreba vytvori aspoò minimálnu bázu vedomostí.

Láskavý èitate¾ mi hádam prepáèi tento vzletný úvod,ktorý je v skutoènosti len chabým pokusom o ospravedl-

nenie sa za prípadné chybné vyriešenie klasického prob-lému, „ako zaèa“. Plne si uvedomujem ve¾ké èasové roz-pätie medzi jednotlivými èasami seriálu na pokraèovaniea budem sa snai do nich zahrnú maximum pouite¾-ných a hlavne konzistentných informácií. Ale dos boloreèí, prejdime koneène k Jave.

Trieda – základ ivotaPrevane teoretickú prvú èas seriálu Java pod lupouzakonèil jednoduchý program "Hello, world", ktorý pospustení vypísal na obrazovku (správnejšie na štandard-ný výstup) tradièný text. Na osvieenie pamäti je tu jehozdrojový text:

public class HelloWorld{

public static void main(String[] args){System.out.println("Hello, world!");

}}

Pozorný èitate¾ si iste spomenie, e zdrojový text tohtoprogramu treba pre úspešné preloenie zapísa do súbo-ru s názvom HelloWorld.java. Preèo je to tak, to si hneï povieme.

 Java je výrazne objektový jazyk. Nie síce v takom roz-sahu ako napríklad v Smalltalku, ale je v tomto smereove¾a dôslednejšia ako C++. Jedným z najdôleitejšíchrozdielov oproti C++ je fakt, e všetok kód v programe je organizovaný výluène do tried. Triedy sú v Jave syn-taktickými konštrukciami a predstavujú šablóny na tvor-

bu objektov. Vieme, e objekty sú charakterizované svo- jím stavom a zoznamom správ, na ktoré dokáu reagova.Stav objektu v Jave je uloený v èlenských premenných jeho triedy, zasielanie správ sa realizuje volaním prísluš-ných metód triedy. Kadá trieda, resp. jej zdrojový kódpreto obsahuje jednak deklaráciu èlenských premenných, jednak deklaráciu metód. Metódy sú v terminológii C++èlenské funkcie tejto triedy.

A propos, termín deklarácia v programovaní znamenáv podstate to isté, èo v reálnom ivote. Deklarácia je vdyspojená s konkrétnym menom a predstavuje vyhlásenie,ako má prekladaè ïalší výskyt tohto mena chápa.Deklarácia èlenskej premennej x tak oznamuje prekla-daèu, e kadý výskyt identifikátora x v príslušnej oblas-ti programu znamená odkaz na túto èlenskú premennú

a na niè iné. Podobne pre deklaráciu metód alebo tried.Povinná organizácia kódu do tried znamená predo-

všetkým to, e v Jave neexistujú globálne premennéa neèlenské funkcie. Táto vlastnos logicky vyplýva z ob- jektovej orientácie Javy a prispieva okrem iného k zní-eniu percenta programových chýb spôsobených neoèa-kávanou a nekonzistentnou manipuláciou s premennýmiz rôznych miest kódu.

Triedy sú v Jave organizované do vyšších celkov, na-zvaných balíky. O balíkoch zatia¾ nebudeme hovori, dô-leité je pre zaèiatok len to, e triedy, ktoré majú by vidi-te¾né (a pouite¾né) aj mimo svojho balíka, musia bydeklarované ako verejné. A tu sa ok¾ukou dostávamek spomínanému obmedzeniu – v Jave platí pravidlo, ev jednom zdrojovom súbore sa môe nachádza deklará-

cia len jedinej verejnej triedy, ktorej meno musí by navy-še totoné s menom súboru bez prípony .java.

Ne¾akajte sa, e zatia¾ nerozumiete, o èom je reè. Zozaèiatku budú ukákové príklady zapísané pomocou jedi-nej verejnej triedy, uloenej v jedinom zdrojovom súbore.Názov tohto súboru preto nebude z dôvodov úsporymiesta odteraz uvádzaný explicitne.

Vráme sa k pôvodnému programu. Ten pozostávaz jedinej triedy s názvom HelloWorld . Ako vidie, deklará-cia tejto triedy sa zaèína k¾úèovým slovom public, ktoréudáva, e pôjde o verejnú triedu. Nad detailmi jeho po-uitia si zatia¾ netreba láma hlavu, v zásade bude programfungova aj bez neho (ale len zatia¾!). Druhé k¾úèové slovoclass urèuje, e ide o deklaráciu triedy. Za ním nasledujenázov deklarovanej triedy, pre ktorý platia rovnaké pra-vidlá ako pre pomenovávanie identifikátorov v mnohýchprogramovacích jazykoch: prvým znakom musí by písme-no, ïalšie znaky môu by aj èíslice. Za písmeno sa v tomtokontexte povauje aj znak _ (podèiarknutie).

Deklarácia èlenov triedy (premenných i metód) je po-vinne uzavretá do zloených zátvoriek ({ a }). Ako uvidí-

me neskôr, takéto zátvorky sa v Jave pouívajú aj v inýchprípadoch; vo všeobecnosti slúia na ohranièenie blokudeklarácií, príkazov a pod. Èitate¾ znalý C++ si isto vši-mol, e za uzatváracou zátvorkou sa v Jave nepíše bodko-èiarka (nikdy).

Trieda HelloWorld  obsahuje jediný èlen: metódumain(). Tento stav nie je nièím výnimoèný – triedy môuobsahova len èlenské premenné, len metódy alebo oboje.Dokonca je moné deklarova triedu, ktorá nebude obsa-

hova nijaké èleny. Praktická pouite¾nos takej triedy jesíce obmedzená, ale nájde sa prípad, keï prázdna triedapostaèí.

Deklaráciu metód zatia¾ nebudeme podrobne rozobe-ra. Ako vidie z príkladu, jej súèasou môe by nieko¾kokvalifikátorov, z ktorých hneï prvý (public) naznaèuje,e metóda main() bude nejakým spôsobom verejná.K¾úèové slovo static v tomto kontexte urèuje, e metódumain() bude moné zavola aj v prípade, e dosia¾ nebu-de existova iadna inštancia triedy HelloWorld .

(Inštancia triedy je objekt vytvorený na základe tejto trie-dy; v Jave je to jednoducho premenná typu tejto triedy.)Metódy tohto typu sa nazývajú metódy triedy (class met-hods), na rozdiel od metód inštancií (instance methods).

Metódy sú v podstate funkciami. Funkcie môu mav programovacích jazykoch (rovnako ako v matematike)argumenty a typicky vracajú návratovú hodnotu. Jedinýmmiestom, kde mono urèi poèet a typ argumentov a typnávratovej hodnoty metód, je ich deklarácia. Metódamain() v uvedenom príklade napríklad pri svojom volaníakceptuje jeden argument pomenovaný args, ktorého typ je „pole reazcov“ (String[]). Po skonèení táto metódanevracia nijakú hodnotu, èo vyjadruje k¾úèové slovo void.

Kód, ktorý tvorí metódu, sa nazýva telo metódy. Tototelo musí by uzavreté do známych zloených zátvoriek.V tele funkcie sa typicky nachádzajú deklarácie lokálnychpremenných a príkazy, ktoré realizujú poadovanú fun-kènos. V príklade HelloWorld metóda main() akýmsi –zatia¾ záhadným – spôsobom zabezpeèí výstup poado-vaného textu na obrazovku. Bez nároku na vysvetlenieprosím èitate¾a o zapamätanie si tohto spôsobu, pretoeho nájde v mnohých ukákových príkladoch.

 Je potrebné spomenú, e metóda main() má v Javepodobné výsadné postavenie ako v C++. Predovšetkým jej deklaráciu (presnejšie jej prototyp – teda názov, poèeta typ argumentov a typ návratovej hodnoty a dokonca ajoba kvalifikátory public a static) treba vdy zapísa takako v uvedenom príklade. Dôvod je prozaický: interpret Javy túto metódu musí vedie nájs, pretoe práve òouzaèína vykonávanie kadej klasickej javovskej aplikácie(pozor, pri appletoch èi servletoch je to ináè). Preto jeostatne táto metóda deklarovaná ako statická (static) –v dobe spustenia programu neexistuje nijaký objekt, nadktorým by mohla by zavolaná.

Do po¾a reazcov args, ktoré má metóda main()dosta ako argument, vloí interpret Javy argumentyprogramu, zadané na príkazovom riadku. I keï tu dochá-dza k drobnej kolízii termínov argument funkcie a argu-ment programu, verím, e èitate¾ nebude zmätený.

Na záver struèného opisu, ako vyzerá deklarácia trieda ich obsahu, je tu krátky program, ktorý mono nájsv mnohých uèebniciach Javy. Pozostáva z jedinej triedyEcho a po spustení vypíše jednotlivé argumenty príkazo-vého riadka, oddelené medzerou:

public class Echo{

public static void main(String[] args){

for (int i = 0; i < args.length; i++)

System.out.print(args[i] + " ");System.out.println();}

}

Kto dával pozor, vie, e zdrojový kód tohto programu tre-ba uloi do súboru Echo.java. Spôsob prekladu a spus-tenia programu bol opísaný v predchádzajúcej èasti seriá-

Obr. 1 Preklad a spustenie programu

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 4/36

JAVA POD LUPOU

4 PC REVUE

lu, ale tu je pre istotu ešte raz: program preloíme pomo-cou nástroja javac, ktorého argumentom musí by názovprekladaného súboru, take na príkazový riadok zapíše-me javac Echo.java. Výstupom prekladu bude súbor sbinárnym obrazom triedy, Echo.class. Vykonanie prog-ramu má na starosti nástroj  java.  Jeho argumentom jevdy názov triedy obsahujúcej metódu main(), alepozor: bez prípony .class! Program Echo preto spustímezadaním java Echo a poadovaných argumentov. Ukáka je na obr. 2. Povšimnite si, prosím, e argumenty príka-zového riadka sú definované ako súvislé úseky textu,oddelené bielymi medzerami. Ak chceme ako argument

odovzda reazec obsahujúci medzery, musíme ho uza-vrie do úvodzoviek.

Lexikálna štruktúra JavyPo praktickom zaèiatku prejdeme teraz k ove¾a teoretic-kejším informáciám. Názov tohto odseku naznaèuje, esa v òom bude hovori o Jave z h¾adiska lexikálnej analý-zy. Lexikálnu analýzu vykonáva prekladaè akéhoko¾vek jazyka pri preklade programu ako úplne prvú a jej cie¾om je transformácia pôvodne neštruktúrovanej postupnostiznakov, uloenej v zdrojovom súbore a tvoriacej textprogramu, na postupnos symbolov (lexikálnych jedno-tiek), ktorým prekladaè rozumie. Súèasou tejto transfor-mácie je, samozrejme, kontrola správnosti programu zh¾adiska „pravopisu“ (to keï omylom napíšeme napríkladpublyc). Po lexikálnej analýze nasleduje syntaktická ana-lýza, ktorá kontroluje dodriavanie gramatiky jazykaa zabraòuje zápisu neplatných konštrukcií.

 Java je ve¾mi mladý jazyk, a preto nikoho neprekvapí,e podporuje štandard Unicode. Èitate¾, ktorému je tentopojem neznámy, nájde blišie informácie na http://www.unicode.org. V skratke mono poveda, e ide oštandard pre jednotné šestnásbitové kódovanie znakovde facto všetkých existujúcich svetových jazykov, resp.ich abecied. Unicode je štandardizovaný organizáciouISO, take sa s ním mono stretnú aj pod názvom ISO10646. V praxi Unicode predstavuje náhradu ASCII a zna-mená koniec rôznym proprietárnym kódovaniam národ-ných znakov a veèným problémom s diakritikou. Naïalších riadkoch èitate¾ nájde zmienku o unikódochnieko¾kých špecifických znakov. Nemusí sa však ¾aka,prvých 256 znakov Unicode je totoných s kódom ASCII(pravdepodobne ISO 8859-1).

Podpora Unicode v Jave je pod¾a špecifikácie ve¾midôsledná. Kdeko¾vek v programe je dovolené pouíva uni-kódové znaky – dokonca aj v názvoch premenných, metódèi samotných tried. V praxi táto podpora silne závisí odkonkrétnej implementácie, pretoe nie kadé runtime pro-stredie si s unikódovými znakmi dokáe poradi stoper-centne. O tom je ostatne moné presvedèi sa pokusomvypísa v ukákovom príklade HelloWorld  reazec obsa-hujúci neanglické unikódové znaky. Po spustení programuv konzolovom okne (resp. DOS boxe) dostaneme namiestovytúeného textu s diakritikou akési èudné znaky, sabyvýsledok nepochopite¾ného prevodu do historickej kódo-vej stránky CP 852 (testované vo Windows 2000 s nastave-ním slovenèiny ako systémového jazyka). Preklad zdrojo-vého textu triedy s ¾ubozvuèným slovenským názvomLíšèí sa síce podaril, ale pokus o jej spustenie sa skonèilv prípade pouitia JDK výnimkou oznamujúcou, epoadovaná trieda sa nenašla. Microsoftovská implemen-

tácia Java VM je na tom lepšie, tej sa triedu Líšèí podariloúspešne nájs, ale výstup unikódového textu na konzoludopadol rovnako neslávne (obr. 3).

Èo z toho vyplýva? Unikódovým znakom v názvochpremenných, metód èi tried sa treba radšej vyhnú.Ostatne je pomerne rozšíreným zvykom pouíva pri ichpomenovávaní angliètinu, ktorá sa bez diakritiky našas-tie zaobíde. S nesprávnym výstupom na konzolu si netre-ba ktovieako láma hlavu, dnes mávajú programy v pre-vanej väèšine grafické pouívate¾ské rozhranie. O pod-pore slovenských znakov v komponentoch GUI si urèiteešte povieme, lebo ani tam situácia nie je ktovieaká ru-ová, ale dá sa aspoò èiastoène ovplyvni.

Vráme sa k lexikálnej analýze. Ako vyplýva z doteraz

povedaného, zdrojový text programu je reprezentovanýpostupnosou unikódových znakov. Jej transformácia napostupnos lexikálnych symbolov sa realizuje v troch kro-koch.

Prvým krokom je preklad unikódových escape sekven-cií na zodpovedajúce unikódové znaky. Unikódové escapesekvencie slúia na zápis znakov pomocou explicitnéhourèenia ich kódu a vo všeobecnosti vyzerajú takto:\uhhhh, kde hhhh je hexadecimálna hodnota znaku. Akovidie, sú podobné escape sekvenciám z jazyka C++(ktoré v Jave tie nájdeme), líšia sa však v mimoriadnedôleitej vlastnosti: mono ich poui kdeko¾vek v prog-rame, nielen v rámci textových reazcov. Ak v ¾ubovo¾nommieste programu pouijeme unikódovú escape sekvenciu,výsledný efekt bude rovnaký, ako keby sme namiesto nejzapísali priamo príslušný znak. Príklad: predpokladajme,e silou-mocou chceme nazva nejakú premennú gréckympísmenom α (alfa). V prípade, e dokáeme zapísa znakα z klávesnice, napíšeme jednoducho do programu nieèoako α = 1. Ak grécku klávesnicu nemáme k dispozícii,budeme si musie vypomôc escape sekvenciou: \u03B1 =

1 (znak α má v unikóde hodnotu 03B1). Oba zápisy súúplne ekvivalentné a v skutoènosti sa poèas prekladuv prvom kroku lexikálnej analýzy transformuje šes zna-kov \ , u, 0, 3, B a 1 pôvodného zdrojového textu na jedi-ný znak α. Táto transformácia je, samozrejme, z h¾adiskaprogramátora úplne transparentná. Treba však podo-tknú, e raz transformované znaky nepodliehajú ïalšejtransformácii, a preto sa zápis \u005Cu03B1 transformu- je na šes znakov \ ,  u, 0, 3, B, 1 (005C  je kód znaku \),ktoré sa u ïalej nenahradzujú a v tejto podobe vstupujúdo ïalšieho kroku lexikálnej analýzy.

V tomto druhom kroku sa postupnos unikódovýchznakov rozdelí na jednotlivé riadky. Java je v tomto smerepomerne nezávislá od platformy a úspešne sa vie vyrovnas odde¾ovaèmi riadkov platforiem DOS/Windows (kombi-nácia CR+LF), Unix/Linux (LF) i Macintosh (CR). Pre úpl-nos: znak CR (carriage return) má v Unicode hexadecimál-ny kód 000D, znak LF (line feed) kód 000A.

Tretím a posledným krokom je rozloenie jednotlivýchriadkov na lexikálne symboly. Aby toho bol prekladaèschopný, musia by tieto symboly nieèím oddelené. Tonieèo sú buï tzv. biele medzery, alebo komentáre.

Termín biela medzera sa pouíva v mnohých progra-

movacích jazykoch a za svoj názov vïaèí faktu, e pritlaèenom výstupe zdrojového textu na biely papier bielemedzery vyzerajú iba ako biele miesta. V Jave sa za bielumedzeru povaujú znaky medzera (SP, unikód 0032),horizontálny tabulátor (HT, unikód 0009), znak „posunstrany“ (form feed, FF, unikód 000C) a takisto všetkyodde¾ovaèe riadkov.

Komentáre sú v Jave prakticky totonés komentármi C++. Povolené sú dvatypy: prvý sa zaèína dvojicou znakov /* akonèí sa znakmi */. Všetko, èo je medzitýmito znakmi, prekladaè ignoruje. Tentotyp nie je povolené vnára do seba – prvývýskyt znakov */ ukonèuje celý komentár.Druhý typ je vhodný na kratšie, jedno-riadkové komentáre, zaèína sa dvojicou

znakov // a za komentár sa povaujú všet-ky nasledujúce znaky a po prvý výskyt odde¾ovaèa riad-kov. Znaky // nemajú nijaký význam vnútri komentárazaèínajúceho sa na /*.

V mnohých uèebniciach Javy mono nájs zmienkuo treom type komentára, tzv. dokumentaènom komen-tári, zaèínajúcom sa znakmi /**. V skutoènosti špecifikácia Javy ako jazyka niè také nepozná a prekladaè nerozlišujemedzi komentármi zaèínajúcimi sa na /* a na /**.Dokumentaèný komentár je pomôcka na automatizovanévytváranie dokumentácie k jednotlivým triedam, ich pre-menným a metódam, spracova ho však dokáe iba samo-statný nástroj javadoc (k dispozícii v rámci JDK). K tomu-to nástroju sa ešte v priebehu seriálu vrátime.

Mnoho programátorov význam komentárov podceòu-

 je. Je moné písa kód samodokumentujúcim spôsobom,keï sa pouívajú skutoène zmysluplné názvy premen-ných èi funkcií a zdrojový text je formátovaný tak, abybol maximálne preh¾adný. To však niè nemení na skutoè-nosti, e èlovek je tvor nedokonalý a detaily implementá-cie projektu, na ktorom pracuje, dokáe po jeho skonèeníve¾mi rýchlo zabudnú. Problém nastáva, ak sa trebak starému kódu vráti, nedajboe ho ešte prepracova.

Malo by by jednou z najdôleitejších zásad progra-mátora, e kód, ktorý tvorí, dostatoène okomentuje.V takej Jave to minimálne znamená opísa, na èo je ktorátrieda urèená, aké sú vstupy a výstupy jednotlivých me-tód a na èo slúia jednotlivé premenné. Programovékonštrukcie je vhodné komentova v prípade, e môev budúcnosti dôjs k nejasnostiam; úplne nevyhovujúcim je z tohto h¾adiska komentár typu „x priraï hodnotu 1“ –takúto informáciu dokáeme zisti aj zo samotného kódu.Komentáre majú vdy predstavova pridanú hodnotu,v tomto prípade informaènú hodnotu.

Program HelloWorld s doplnenými komentármi byteda mohol vyzera napríklad takto:

 /** HelloWorld** Ukákový príklad výstupu textu na konzolu*/

public class HelloWorld{

 //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− // main()

 // // vstup: args − argumenty príkazového riadka // výstup: iaden //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−public static void main(String[] args){

System.out.println("Hello, world!");}

}

Lexikálne symbolyVýstupom lexikálnej analýzy pri preklade programu jepostupnos lexikálnych symbolov jazyka. Tieto symbolymono v Jave rozdeli na pä druhov: k¾úèové slová, iden-tifikátory, literály, operátory a odde¾ovaèe.

 K¾úèové slová sú reazce znakov, ktoré majú v Jave

rezervovaný význam a nemono ich poui inak, naprí-klad ako názov premennej. S nieko¾kými k¾úèovými slo-vami sme sa u stretli: public, void, class.

 Identifikátory sú svojím spôsobom vlastne mená. Menátried, rozhraní, premenných èi metód. Kadá údajová èikódová entita v Jave musí ma svoje pomenovanie, ano-

Obr. 2

Obr. 3

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 5/36

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 6/36

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 7/36

Pozornému èitate¾ovi isto neunikla skutoènos, edosia¾ sme nehovorili o type, ktorý by reprezentoval tex-tové reazce. V jazyku C++ je reazec znakov realizova-ný ako pole znakov, ukonèené nulovou hodnotou. Tentospôsob je síce pomerne efektívny, ale vzh¾adom na nija-ko neošetrovanú prácu s po¾ami aj znaène náchylný nave¾mi ako odhalite¾né chyby. A to u vôbec nehovorímeo praktickej nutnosti pouíva pri práci s reazcami (a po-¾ami všeobecne) ukazovatele, ktoré sa pri len trochu zlo-

itejších údajových štruktúrach rýchlo stanú noènoumorou menej skúseného programátora.

 Java prináša znièenému vývojárovi vytúenú ú¾avuv podobe realizácie textových reazcov ako objektov,konkrétne inštancií triedy String. Táto trieda okremfaktu, e oslobodzuje programátora od starostí o detailyskutoènej implementácie, poskytuje aj širokú škálumetód na prácu s reazcami. Trieda String má urèitýmspôsobom výnimoèné postavenie, pretoe sa od ostat-ných tried líši v drobných detailoch pouitia. Konkrétnekadý výskyt reazcového literálu v programe automatic-ky predstavuje inštanciu triedy String a navyše je na spá- janie reazcov (a nielen reazcov medzi sebou, ale ajreazca a ¾ubovo¾nej hodnoty; pozri uvedené príklady)moné poui operátor +.

Tu je príklad práce s premennou typu String:

String s = "5 * 13 = ";int x;x = 5 * 13;System.out.println(s + x);

Program po spustení vypoèíta súèin hodnôt 5 a 13 avypíše výsledok:

5 * 13 = 65

To, èo odlišuje referenèné typy od primitívnych, je fakt, ekadá premenná alebo výraz referenèného typu obsahujev skutoènosti odkaz na objekt uloený kdesi inde v pamä-ti. Opä si môeme vypomôc analógiou s C++ – refe-

renèné typy sú v zásade totoné s referenciami jazykaC++, s tým rozdielom, e v C++ mono deklarova ajreferencie na typy, ktoré v Jave povaujeme za primitívne.

Zhròme teda rozdiely: v premennej primitívneho typu je uloená priamo poadovaná hodnota. Ak máme naprí-klad premennú typu long, bude táto premenná v pamätiuloená ako postupnos 64 bitov, obsahujúcich binárnureprezentáciu jej obsahu. Naproti tomu v premennej refe-renèného typu je uloená len adresa miesta v pamäti, kdenájdeme objekt, ktorý táto premenná „obsahuje“. Inýmislovami, nezávisle od svojho typu bude kadá referenènápremenná v pamäti zabera rovnaké miesto, so šírkouzávisiacou od šírky pamäovej adresy na danej imple-mentácii Java VM. Vzh¾adom na to, e akýko¾vek prístupk referenènej premennej automaticky pracuje s odkazo-

vaným objektom, nie je moné a z bezpeènostného h¾a-diska ani iaduce uloenú adresu zisti.

Praktickým dôsledkom odlišnosti medzi primitívnymia referenènými typmi je skutoènos, e sa dve rôzne refe-renèné premenné môu odkazova na rovnaký objektv pamäti. Ukáme si to na príklade:

public class Test{

public static void main(String[] args){

int[] a = { 1, 2, 3 };int[] b = a;a[1] = 222;System.out.println("a[1] = " + a[1]);System.out.println("b[1] = " + b[1]);

}}

Ak skúsite preloi a spusti tento program, dostanetenasledujúci výstup:

a[1] = 222;

 b[1] = 222;

 Je oèividné, e premenné a aj b odkazujú na to i sté pole– pri zmene prvku a[1] súèasne došlo k zmene prvku b[1].

Výrazy a operátorySpomínali sme u, e prakticky kadý program nejakýmspôsobom pracuje s údajmi. Kadý krok spracovania úda- jov treba nejakým spôsobom zapísa. Ak napríklad poèí-

tame korene kvadratickej rovnice, musíme do programuvloi jednak postup výpoètu diskriminantu, jednakvýpoèet samotných koreòov a pri skutoène univerzálnomprograme nezabudneme zisti, èi rovnica náhodou nemákomplexné korene. Všetky tieto matematické (a iné)operácie zapisujeme prakticky v kadom programova-com jazyku pomocou výrazov.

Kadý výraz sa skladá z operátorov a ich operandov.Operátor je symbol, ktorý urèuje typ operácie vykonáva-nej s príslušnými údajmi, ako napríklad + pre sèítanie.Údaje, ktoré do operácie vstupujú, sa nazývajú operandydaného operátora. Operátory môu ma jeden, dva èi trioperandy. Pod¾a toho ich delíme na unárne, binárne a ter-nárne. Operátor + je napríklad binárny operátor, pretoením sèítavame dve èísla.

Výskyt akéhoko¾vek výrazu v programe vedie k jehovyhodnoteniu. Pod vyhodnotením výrazu sa rozumie po-stupná aplikácia jednotlivých operátorov na ich operandy,a kým sa výraz nezredukuje na jedinú hodnotu, ktorábude hodnotou celého výrazu. Tak napríklad vo výraze2 + 3 * 4 sa aplikuje operátor * na operandy 3 a 4, èímdostaneme hodnotu 12, a v druhom kroku sa operátor +aplikuje na operandy 2 a 12. Hodnotou výrazu 2 + 3 * 4bude teda 14.

Poradie, v ktorom sa operátory aplikujú, je dané ichprioritou. Tabu¾ku priorít jednotlivých operátorov si uve-dieme po ich postupnom prebratí. Explicitne môemehierarchiu priorít zmeni pomocou zátvoriek, podobneako v matematike. Operandy kadého operátora sa v Javevyhodnocujú  vdy  z¾ava doprava. Tento princíp mono

ilustrova nasledujúcim príkladom:

int i = 3;int j = (i = 2) * i;System.out.println(j);

Po preloení a spustení program vypíše:

4

V príklade chceme premennej j priradi hodnotu výrazu(i = 2) * i. Vidíme, e máme vo výraze operátor násobe-nia * s dvoma operandmi. Vzh¾adom na uvedené pravid-lo sa najprv vyhodnotí operand (i = 2), ktorý priradí pre-mennej i hodnotu 2. Výslednou hodnotou tohto operan-du bude priraïovaná hodnota, teda 2. A potom sa zaène

vyhodnocova druhý operand i, ktorého hodnota budetriviálne hodnotou premennej i. Ale tej sme predsa predchví¾ou priradili hodnotu 2! Preto výslednou hodnotoudruhého operandu bude 2 a výsledok celého výrazu buderovný èíslu 4.

Aditívne operátoryPrvými dvoma operátormi, o ktorých si povieme, sú tzv.aditívne operátory + a -. Oba operátory sú binárne a slú-ia na realizáciu tých najjednoduchších matematickýchoperácií – sèítania a odèítania. Majú rovnakú prioritua asociujú sa z¾ava doprava. Asociatívnos operátorov vy- jadruje postupnos vyhodnocovania operátorov s rovna-kou prioritou. Napríklad výraz 2 + 3 + 4 sa vzh¾adom naasociatívnos z¾ava doprava operátora + vyhodnotí tak,

akoby sme ho zapísali (2 + 3) + 4. Keby sa operátor +asocioval opaène, sprava do¾ava, výraz by sa vyhodnoco-val ako 2 + (3 + 4). Zátvorky, pochopite¾ne, explicitneurèujú prioritu.

Pri sèítaní a odèítaní celých èísel môe dôjs k preteèe-niu èi podteèeniu povoleného rozsahu. Tento stav sa nija-

ko nesignalizuje a je len na programátorovi, aby s nímv prípade potreby poèítal. Ako príklad mono uvies taký-to kód:

int a = 1000000000;int b = 2000000000;System.out.println(a + b);

Výstupom programu bude:

−1294967296

Skutoèný výsledok sèítania hodnôt premenných a a b  jemimo rozsahu typu int. Výsledok, ktorý dostaneme akovýstup programu, vznikne ignorovaním preteèenýchbitov. Podobná situácia nastáva pri odèítaní.

Pre sèítanie èísel s pohyblivou èiarkou platia urèitépravidlá (pod¾a štandardu IEEE 754): Ak je niektorým operandom hodnota NaN, výsledokbude takisto NaN. Súètom dvoch nekoneèien s rovnakým znamienkom jenekoneèno s týmto znamienkom. Súètom dvoch nekoneèien s opaèným znamienkom jeNaN. Súètom nekoneèna a koneènej hodnoty je to isté neko-

neèno. Súètom dvoch núl s rovnakým znamienkom je nulas týmto znamienkom. Súètom dvoch núl s opaèným znamienkom je kladnánula. Súètom nuly a koneènej hodnoty je tá istá koneèná hod-nota. Súètom dvoch koneèných hodnôt s rovnakou absolút-nou hodnotou a opaèným znamienkom je kladná nula.

Tieto pravidlá sa súèasne vzahujú na odèítanie,pretoe pre èíselné typy bez výnimky platí, e výraz a –b dáva rovnaký výsledok ako a + (-b).

Oba operandy operátorov + aj - musia by primitív-ne èíselné typy, s jedinou výnimkou, o ktorej sme uèiastoène hovorili. Ak je aspoò jedným z operandov

operátora + typ String, prevedie sa prípadne druhýoperand takisto na typ String a výsledkom bude spoje-nie oboch reazcov.

Multiplikatívne operátoryDo tejto triedy patria operátory *, / a %, slúiace po radena výpoèet súèinu, podielu a zvyšku po delení dvochèísel. Všetky tri operátory majú rovnakú prioritu a aso-ciujú sa z¾ava doprava. Operandy týchto operátorov mu-sia by povinne èíselného primitívneho typu.

Pre násobenie èísel s pohyblivou èiarkou platia tietopravidlá: Ak je niektorým operandom operátora * hodnota NaN,výsledok bude takisto NaN. Ak výsledkom násobenia nie je hodnota NaN, znamien-ko výsledku bude podobne ako v matematike kladné, akmajú oba operandy rovnaké znamienko, a záporné, akmajú znamienko opaèné. Súèinom nekoneèna a nuly je NaN. Súèinom nekoneèna a koneènej hodnoty je nekoneèno.

Pri výpoète súèinu môe dôjs k preteèeniu èi podteèe-niu; preteèené bity sa opä ignorujú.

Operátor delenia sa správa trochu rozdielne v závis-losti od typu svojich operandov. Výsledkom deleniadvoch celých èísel je podobne ako v C++ opä celé èíslo,ktoré vznikne zo skutoèného podielu odstránením desa-tinnej èasti. Ukáka:

int a = 13;int b = 3;

System.out.println(a / b);

Tento úsek programu vypíše:

4

Ïalej, ak sa pokúsime deli akéko¾vek celé èíslo nulou,

JAVA POD LUPOU

PC REVUE 7

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 8/36

dôjde k chybe, tzv. výnimke. (Výnimky v Jave slúia nasignalizáciu chybových stavov. Povieme si o nich viacv budúcnosti.) Ak však budeme deli nulou èíslo s pohyb-livou èiarkou, k chybe nedôjde. To je ostatne jednýmz dôsledkov nasledujúcich pravidiel: Ak je niektorým operandom operátora  / hodnota NaN,výsledok bude takisto NaN. Ak výsledkom delenia nie je hodnota NaN, znamienkovýsledku bude kladné, ak majú oba operandy rovnaké

znamienko, a záporné, ak majú znamienko opaèné. Delenie nekoneèna nekoneènom dáva výsledok NaN. Delenie nekoneèna koneènou hodnotou dáva opänekoneèno. Delenie koneènej hodnoty nekoneènom dáva nulu. Výsledkom delenia dvoch núl je NaN, výsledkom dele-nia nuly a koneènej hodnoty je opä nula. Koneène delenie koneènej hodnoty nulou dáva akovýsledok nekoneèno.

Preteèenie èi podteèenie sa opätovne ignoruje.Tretí operátor % slúi na výpoèet zvyšku po delení dvochèísel. Na rozdiel od C++ jeho operandmi môu by ajèísla s pohyblivou èiarkou. Výsledkom aplikácie tohtooperátora je hodnota, ktorá vyhovuje rovnosti

(a / b) * b + (a % b) = a. Znamienko zvyšku je zhodné soznamienkom delenca (t. j. ¾avého operandu).

Pri snahe o výpoèet zvyšku po delení celého èísla nu-lou nastane výnimka, pri výpoète zvyšku po delení èísels pohyblivou èiarkou platia tieto pravidlá: Ak je niektorým operandom operátora % hodnota NaN,výsledok bude takisto NaN. Ak výsledkom výpoètu zvyšku nie je hodnota NaN, zna-mienko výsledku je zhodné so znamienkom delenca. Ak je delencom nekoneèno alebo ak je delite¾om nula(alebo v oboch prípadoch), výsledok bude NaN. Ak je delencom koneèná hodnota a delite¾om nekoneè-no, výsledok je rovný delencu. Ak je delencom nula a delite¾om koneèná hodnota,výsledok bude nulový.

Pri výpoète zvyšku k preteèeniu èi podteèeniu nemôedôjs. Príklad všetkých kombinácií kladného a zápornéhooperandu:

System.out.println( 13 % 3);System.out.println( 13 % −3);System.out.println(−13 % 3);System.out.println(−13 % −3);

Výstupom takéhoto úseku programu budú èísla:

11−1−1

Unárne plus a mínusÏalšie dva operátory sú ve¾mi triviálne: ide o unárne plus(+) a unárne mínus (-). Oba operátory sa asociujú spravado¾ava. Ich jediný operand musí ma èíselný primitívnytyp. Unárne plus vo svojej podstate nerobí niè okremtoho, e podobne ako iné aritmetické operátory automa-ticky rozširuje typ svojho operandu. Táto konverzia jevšak prirodzená a ešte si o nej budeme hovori. Prakticképouitie unárneho + sa obmedzuje azda len na explicit-né zdôraznenie kladnosti nejakej konštanty a pod.

Unárne mínus v zásade mení znamienko svojho ope-randu. To platí tak pre celoèíselné typy, ako aj pre typys pohyblivou èiarkou. Špeciálne hodnoty, ako nula èinekoneèno, nevykazujú v tomto prípade nijaké odlišnos-ti. Jediným rozdielom je aplikácia unárneho - na hodnotu

NaN, vtedy je výsledkom opä NaN.Operátory ++ a ––Posledné dva operátory, o ktorých bude v tejto èasti reè,slúia na inkrementáciu (+s+) a dekrementáciu (––) pre-menných. Inkrementova premennú znamená zvýši jejhodnotu o 1, dekrementácia predstavuje, naopak,

zníenie hodnoty o 1. Oba operátory sú unárne a existu- jú v dvoch variantoch: prefixovom (operátor je pred ope-random) a postfixovom (operátor je za operandom). Ich jediným operandom musí  povinne by premenná èísel-ného typu.

Výsledný efekt aplikácie prefixového a postfixovéhovariantu operátora ++, resp. --  je rovnaký: inkrementá-cia, resp. dekrementácia. Oba varianty však sa líšiavýslednou hodnotou výrazu obsahujúceho príslušný

operátor. Pri pouití postfixového variantu je výsledkomvýrazu hodnota premennej  pred inkrementáciou/dekre-mentáciou, pri pouití prefixového variantu je výsledkomvýrazu hodnota premennej  po inkrementácii/dekremen-tácii. Ukáme si to na príklade:

int a = 3;int b = 3;System.out.println(a++);System.out.println(++b);System.out.println(a);System.out.println(b);

Uvedený fragment kódu po spustení vypíše na obrazovkuèísla:

3444

Ako vidie, výsledná hodnota premenných a aj b bude poinkrementácii 4. Výraz a++ však vráti hodnotu a predinkrementáciou, èo je 3, výraz ++b vráti hodnotu b poinkrementácii a to je u spomínaných 4. Rovnaký príkladsi mono vyskúša pre operátor dekrementácie --.

Operátory ++ a -- v Jave vykazujú jeden podstatnýrozdiel oproti C++: v C++ vracia prefixový variantoboch operátorov l-hodnotu, predstavujúcu inkremento-vanú/dekrementovanú premennú, ktorej je tak monépriradi inú hodnotu. V Jave je výsledkom aplikácieoperátorov vdy hodnota, nikdy nie premenná, preto

výraz ++a = 3 je v Jave chybný.Prefixové varianty oboch operátorov sa asociujú spra-

va do¾ava, to znamená, e výraz -++a sa vyhodnotí ako-(++a). Pri postfixových variantoch o asociácii nemázmysel hovori, dôleité je vedie, e tieto operátorymajú pomerne ve¾kú prioritu. Ale k tomu sa ešte dosta-neme.

4.èas : Operá tory (pokraèovanie)

Vo štvrtej èasti seriálu, poslednej v tomto storoèí,pokraèujeme opisom operátorov, ktoré jazyk Java posky-tuje programátorovi na prácu s údajmi. Dosia¾ sme pre-brali základné aritmetické operátory +, -, *, / a % a dvaoperátory inkrementácie/dekrementácie ++ a --.

Relaèné operátoryÏalšou skupinou operátorov sú tzv. relaèné operátory.Pojem relácia bude laikovi pravdepodobne evokova neja-ký vzah. Skutoène, relaèné operátory v Jave slúia na zis-tenie, èi sú dva výrazy v poadovanom vzahu. Relácie,ktoré tieto operátory rozpoznávajú, sú dobre známez matematiky: ide o rovnos a ostrú a neostrú nerovnos.

Operátory testujúce nerovnos dvoch výrazov sú štyri:<, <=, >, >=. Vzahy, ktoré reprezentujú, sú po rade„menší“, „menší alebo rovný“, „väèší“ a „väèší aleborovný“. Znaky operátorov neostrej nerovnosti <= a >=treba zapisova v uvedenom poradí, nikdy nie naopak.

Všetky štyri operátory sú binárne. Ich operandy musiaby povinne primitívne èíselné typy a výsledok je vdytypu boolean. Z toho vyplýva, e i keï sa asociujú z¾avadoprava, nemá asociácia v tomto prípade nijaký význam,pretoe zápis a < b < c povedie k chybe pri preklade(a < b je typu boolean, ktorý nemono porovnáva s pre-mennou c, nech by bola akéhoko¾vek typu).

V prípade, e porovnávame výrazy typu float alebodouble, je výsledkom NaN, ak je aspoò jeden z operandovNaN. Na úèely porovnávania prostredníctvom operátorov<, >, <= a >= sú èísla „kladná nula“ a „záporná nula“rovné a výraz -0.0 < +0.0 vráti false.

Ïalšie dva relaèné operátory, == a !=, zisujú rov-nos, resp. nerovnos dvoch výrazov. Oba sú navzájomkomplementárne a vdy platí, e a!=b má rovnakú hod-notu ako !(a==b). Aj tieto operátory sú binárne a ich

výsledok je vdy typu boolean. Èo sa však týka typu ichoperandov, máme k dispozícii trochu širšiu oblaspouitia.

Predovšetkým môu by operandmi == a != primi-tívne èíselné typy. Pri porovnávaní výrazov typufloat/double platí, e ak je aspoò jeden z operandov NaN,výsledok ==  je false, výsledok !=  je true. Kladnáa záporná nula sú povaované za navzájom rovné.

Druhá monos je porovnáva operandy typu boolean.Za pozornos stojí, e v takom prípade je výsledok operá-tora != totoný s výsledkom operátora ^ (pozri ïalej).

Koneène môeme pomocou operátorov == a !=porovnáva výrazy referenèných typov. Treba si rýchlospomenú na predchádzajúcu èas seriálu, kde sme uvied-li, e premenné referenèných typov obsahujú iba adresu,

odkaz na skutoèné údaje, uloené niekde inde v pamäti.(Na zopakovanie: referenènými typmi sú v Jave objekty[inštancie tried] a polia). Po krátkej úvahe dospejemek záveru, e operátor == aplikovaný na dve premennéreferenèného typu vráti true len vtedy, ak obe premennébudú ukazova na jeden a ten istý objekt èi pole. Operátor!= v takom prípade vráti, pochopite¾ne, false.

Relaèné operátory sa pouívajú najmä v podmienko-vých výrazoch príkazov if , for  èi  while. Príkazom Javybudeme venova samostatnú èas seriálu, preto na demo-nštráciu aplikácie operátorov pouijeme len takýto jed-noduchý príklad:

int a = −5;int b = 14;

System.out.println("(a < b) = " + (a < b));System.out.println("(a <= b) = " + (a <= b));System.out.println("(a > b) = " + (a > b));System.out.println("(a >= b) = " + (a >= b));System.out.println("(a == b) = " + (a == b));System.out.println("(a != b) = " + (a != b));

 boolean c = true; boolean d = false;System.out.println("(c == d) = " + (c == d));System.out.println("(c != d) = " + (c != d));

int pa[] = { 1, 2, 3 };int pb[] = pa;int pc[] = { 1, 2, 3 };System.out.println("(pa == pb) = " + (pa == pb));System.out.println("(pa == pc) = " + (pa == pc));

Výsledkom aplikácie jednotlivých operátorov budú porade literály true, true, false, false, false, true (prvá èasprogramu), false, true (druhá èas programu) a true,false (tretia èas programu). Ako vidie, premenné pa apb ukazujú na to isté pole, preto sa z poh¾adu operátora== navzájom „rovnajú“. Premenné pa a pc sa však„nerovnajú“ napriek tomu, e polia, ktoré reprezentujú,majú rovnaké hodnoty prvkov. Vyskúšanie aplikácieoperátorov na iné hodnoty ponechávam na èitate¾ovi.

Aby bolo vymenovanie relaèných operátorov úplné,nesmieme vynecha operátor instanceof , ktorý pomôepri zisovaní skutoèného typu výrazu. To však platí len prereferenèné typy, výrazy primitívnych typov takto identifi-kova nemono. Operátor instanceof je binárny, ¾avýmoperandom musí by výraz referenèného typu, pravýmoperandom je literál predstavujúci vyšetrovaný typ. Ak jetyp ¾avého operandu zhodný s pravým operandom, výsled-kom je hodnota true, inak je výsledkom false.

Typickým príkladom pouitia môe by obsluná ruti-na nejakej udalosti grafického pouívate¾ského rozhra-nia, ktorá zisuje, ktorý prvok GUI má udalos „na svedo-

8 PC REVUE

JAVA POD LUPOU

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 9/36

mí“:

if (sender instanceof Button){

 // ...}

Predpokladáme, e premenná sender obsahuje odkaz naobjekt predstavujúci prvok GUI, ktorý udalos spôsobil.Trieda Button by mohla reprezentova prvky typu „tlaèid-

lo“, potom bude uvedený príkaz if testova, èi je zdrojomudalosti niektoré tlaèidlo.

Bitové a logické operátoryPodobne ako C++ mono nájs v Jave nieko¾ko operáto-rov, ktoré pracujú s bitovou reprezentáciou èísel. Jednot-livé bity celoèíselných premenných èi hodnôt môemepovaova za logické premenné a aplikova na ne základ-né funkcie boolovskej algebry: logický súèin (AND), logic-ký súèet (OR), exkluzívny logický súèet (takisto nonekvi-valencia – XOR) a negáciu (NOT). Pre tieto štyri logickéfunkcie sú v Jave urèené štyri operátory: &, |, ^ a ~.V tabu¾ke nájde èitate¾ funkèné hodnoty logických funk-cií pre jednotlivé kombinácie bitových hodnôt.

 Logické funkcie

Operátory majú prívlastok bitové z toho dôvodu, erealizujú logické funkcie bit po bite, vdy medzi zodpo-vedajúcimi bitmi svojich operandov (výnimkou je, samo-zrejme, operátor negácie, ktorý je unárny a má len jedi-ný operand).

Operátor bitového logického súèinu & slúi na výpoèetlogického súèinu dvoch celoèíselných hodnôt. Ide tedao binárny operátor, ktorý sa asociuje podobne ako aditív-ne èi multiplikatívne operátory z¾ava doprava. Príkladlogického súèinu dvoch premenných typu int:

int a = 0x3CA8;int b = 0xCAFE;int c = a & b;System.out.println("a & b = " + c);

Výstupom tohto programu bude èíslo 2216, hexadecimál-ne 0x08A8, ktoré je skutoène výsledkom logického súèi-nu hodnôt 0x3CA8 a 0xCAFE, o èom sa môeme ¾ahkopresvedèi prepísaním hodnôt premenných a a b avýsledku c do dvojkovej sústavy.

Argumentmi operátora & môu by okrem celoèísel-ných hodnôt èi premenných aj premenné a hodnoty typuboolean. Tie, ako vieme, sú široké len jeden bit. Logickýsúèin sa realizuje nad týmto jediným bitom a výsledky súv zhode s tabu¾kou 1, len s tým rozdielom, e namiestoèíselných hodnôt 0 a 1 uvaujeme pri logických premen-ných literály false a true. O tom ostatne svedèí nasledu- júci úsek programu:

System.out.println("true & false = " + (true & false));

ktorého výstupom bude, pochopite¾ne, literál false.Operátor bitového logického súètu  | realizuje výpoèet

logického súètu jednotlivých bitov svojich dvoch operan-dov. Opä ide o binárny operátor s asociáciou z¾avadoprava. Pouitie ukáeme na modifikácii predchádzajú-

ceho príkladu:

int a = 0x3CA8;int b = 0xCAFE;int c = a | b;System.out.println("a | b = " + c);

Tentoraz je výstupom hodnota 65278, hexadecimálne0xFEFE. O správnosti výsledku sa opätovne mono pre-svedèi prepisom hodnôt do dvojkovej sústavy.

Aj operátor | dokáe spracova logické premenné typuboolean. Výstupom nasledujúceho riadka:

System.out.println("true | false = " + (true | false));

 je teda literál true.

Operátor bitového exkluzívneho logického súètu ^ násu iste nièím neprekvapí. Slúi na výpoèet funkcie XOR,ktorá na rozdiel od funkcie OR (tzv. inkluzívneho logic-kého súètu) vyluèuje súèasnú platnos oboch svojichargumentov. (To je ostatne jediný bod, v ktorom sa XOR líši od OR.) Aj tento operátor je binárny a asociuje saz¾ava doprava. Obligátny príklad:

int a = 0x3CA8;int b = 0xCAFE;int c = a ^ b;System.out.println("a ^ b = " + c);

Program poskytne výsledok 63062, hexadecimálne0xF656.

Ani operátor ^ nám neodoprie monos aplikova ho

na hodnoty typu boolean:

System.out.println("true ^ true = " + (true ^ true));

Ako uvidíme po spustení, exkluzívnym logickým súètomdvoch hodnôt true je presne pod¾a predpokladov hodno-ta false.

Operátor bitovej negácie   ~ našastie trochu narúšadoterajší stereotyp. Ako vyplýva z povahy negácie, tentooperátor bude unárny a asociova sa bude podobne akoiné unárne operátory sprava do¾ava. Aplikova ho všakmôeme výhradne na premenné celoèíselného typu:

int a = 0x3CA8;int b = ~a;System.out.println("~a = " + b);

Výstupom bude bitová negácia hodnoty 0x3CA8, èo jedekadicky -15529 (typ int je znamienkový, spomínate si?)a hexadecimálne 0xFFFFC357 (pretoe typ int má šírku32 bitov).

Ve¾ký pozor si treba da pri pokuse o negáciu premen-ných typu boolean. V takom prípade toti nemonopoui operátor bitovej negácie   ~. Našastie Java jev tomto smere oh¾aduplná a ako náhradu ponúka operá-tor logickej negácie !. Pre tento operátor inak platí všet-ko, èo sme uviedli o operátore ~. Ešte krátky príklad:

System.out.println("!true = " + !true);

Ako sa môeme presvedèi, negáciou hodnoty true  je

(prekvapujúco :) hodnota false.V Jave podobne ako v C++ existujú okrem bitovýchoperátorov logického súèinu & a logického súètu | ešteiné dva logické operátory && a ||, realizujúce na poh¾adrovnaké logické funkcie. Oba operátory sú binárne a aso-ciujú sa z¾ava doprava, ich operandy však musia by typuboolean. Okrem toho sa operátory && a || líšia od svo- jich jednoznakových náprotivkov v pomerne zásadnejveci: spomeòme si, e operandy operátora sa v Javevyhodnocujú vdy z¾ava doprava. Ak sa však ¾avý ope-rand operátora && vyhodnotí ako false, výsledok unemôe by iný ako false, preto sa pravý operand aninevyhodnocuje. Podobne operátor ||: ak má jeho ¾avýoperand hodnotu true, výsledok bude za kadých okol-ností true a pravý operand sa nevyhodnotí.

Na demonštráciu uvedených vlastností operátorov &&a || slúi nasledujúci príklad:

int i = 10; boolean never = false; boolean r1 = (i < 0) && (never = true);

 boolean r2 = (i > 0) || (never = true);System.out.println("r1 = " + r1 + ", r2 = " + r2);System.out.println("never = " + never);

Výstup programu:

r1 = false, r2 = truenever = false

nám potvrdí, e pri vyhodnocovaní výrazov priraïujúcich

hodnoty premenným r1 a r2 sú výsledky známe u povyhodnotení príslušných podmienok a k priradeniu truedo premennej never nikdy nedôjde.

Èitate¾ ovládajúci C++ si azda v súvislosti s operátorom&& všimne zásadný rozdiel medzi C++ a Javou. V C++môu by operandy && ¾ubovo¾ného èíselného typu.Zoberme si teda napríklad èísla 5 a 10. Výraz 5 && 10  jevyhodnotený ako pravdivý (jeho hodnota je 1), zatia¾ èovýraz 5 & 10  je vyhodnotený ako 0, pretoe oba operandymajú spodné štyri bity „na preskáèku“ (0101 a 1010). V Javeoperandy && môu by iba typu boolean a výsledok apliká-cie operátora && bude rovnaký ako výsledok aplikácie &, roz-diel je len v prípadnom skrátenom vyhodnocovaní. Zatia¾ èoteda v C++ je potrebné podmienky reazi operátorom &&(ako napr. a >= 100 && a < 200), v Jave môeme poui aj

operátor &. Pozor treba da iba na to, aby výsledok aplikácie& bol typu boolean, pretoe podmienkové výrazy v príka-zoch if , while a pod. musia by výhradne typu boolean.

Praktická aplikácia bitových operátorovBitové operátory &, | a ^ mono s úspechom poui primanipulácii s jednotlivými bitmi celoèíselných premen-ných. V praxi sa obyèajne vyskytne potreba vybrané bityurèitej premennej nastavi, vynulova alebo preklopi doopaèného stavu. Ostatné bity by sme radi ponechaliv pôvodnom stave. Riešenie tejto úlohy je pomerne jed-noduché, staèí dobre ovláda vlastnosti logických funkcií.

Pre nastavenie vybraných bitov s úspechom vyuijemefunkciu logického súètu OR. Ako vyplýva z tabu¾ky jejfunkèných hodnôt (tab. 1), logický súèet s jednotkovým

bitom je vdy jednotka, logický súèet s nulovým bitompôvodný bit nemení. Ako druhý operand operátora | tedapouijeme èíslo, v ktorom sú jednotkové tie bity, ktoréchceme nastavi, a nulové všetky ostatné. Príklad:

 byte b = 0x29;System.out.println("b | 0x07 = " + (b | 0x07));

Chceme nastavi spodné tri bity, pouijeme teda èíslo0x07. Výsledok bude pod¾a oèakávania èíslo 0x2F (resp.47 dekadicky).

Na nulovanie vybraných bitov sa hodí funkcia logickéhosúèinu AND. Logický súèin ¾ubovo¾nej hodnoty s nulou jevdy nula, logický súèin s jednotkou pôvodný bit zacho-vá. Tentoraz teda pouijeme ako druhý operand operáto-

ra & èíslo, v ktorom sú nulové tie bity, ktoré potrebujemevynulova; ostatné bity zadáme jednotkové. Príklad:

 byte b = 0x29;System.out.println("b & 0xF8 = " + (b | 0xF8));

Tentoraz chceme vynulova spodné tri bity, vhodnýmoperandom bude èíslo 0xF8. Výsledkom je hodnota 0x28alebo dekadicky 40.

Koneène negáciu vybraných bitov realizujeme pomocoufunkcie exkluzívneho logického súètu XOR. Tá má túvlastnos, e ak XORujeme ¾ubovo¾ný bit s jednotkou,výsledkom je presne opaèná hodnota. Nula pôvodný bitnemení. Operand operátora ^ vytvoríme rovnakým spô-sobom ako pri nastavovaní bitov. Príklad:

 byte b = 0x29;System.out.println("b ^ 0x07 = " + (b ^ 0x07));

Opätovne pouijeme èíslo 0x07, výsledkom negácie spod-ných troch bitov hodnoty 0x29 bude èíslo 0x2E, dekadic-ky 46.

PC REVUE 9

JAVA POD LUPOU

AND OR XOR NOT

a b a & b a | b a ̂ b ~a

0 0 0 0 0 1

0 1 0 1 1 1

1 0 0 1 1 0

1 1 1 1 0 0

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 10/36

Èíslo, ktoré pouívame ako druhý operand operátorov&, | a ^, sa nazýva maska. Je vhodné uloi si masku dosamostatnej premennej (prípadne konštantnej premen-nej – uvidíme neskôr, ako ju deklarujeme). Potom jumôeme pouíva ve¾mi elegantným spôsobom:

final byte MASK = 0x07; b = b | MASK; // nastavenie b = b & ~MASK; // nulovanie b = b ^ MASK; // negácia

Všimnite si, ako dosiahneme príslušnú masku na nulova-nie bitov – jednoducho masku uloenú v premennejMASK negujeme pomocou operátora ~. Výsledkom negá-cie 0x07 je, samozrejme, hodnota 0xF8.

Nakoniec treba podotknú, e uvedené príklady praco-vali s osembitovými hodnotami typu byte. Pri pouitíiných typov (short, int, long) treba ráta so širším rozsa-hom, ale princíp zostáva rovnaký.

Operátory bitového posunuPri operátoroch, ktoré berú do úvahy bitovú reprezentá-ciu èísel, ešte chví¾u zostaneme. V praxi obèas nastanesituácia, e potrebujeme zmeni hodnotu nejakej pre-mennej takým spôsobom, aby jej jednotlivé bity zmenilisvoju polohu o jednu èi viac pozícií do¾ava alebo doprava.

Operátory bitového posunu sú tri: operátor posunuv¾avo <<, operátor znamienkového posunu vpravo >>a operátor neznamienkového posunu vpravo >>>.Všetky tri operátory sú binárne a asociujú sa z¾ava dopra-va. ¼avým operandom je posúvaná hodnota, pravým ope-random je poèet pozícií, o ktorý sa bity posunú. Typyoboch operandov musia by celoèíselné.

Pri posune v¾avo bity, ktoré z èísla „vyliezajú“ na¾avom konci, miznú do nenávratna, sprava sa prisúvajúnuly. Pri posune vpravo so znamienkom (operátor  >>)konèia svoju existenciu bity vychádzajúce na pravomkonci, z¾ava sa prisúva bit zhodný s najvyšším, t. j. zna-mienkovým bitom pôvodnej hodnoty (iný poh¾ad: najvyš-ší bit zostáva na svojom mieste a do posunu posiela svojukópiu). Posun vpravo bez znamienka (operátor >>>) salíši od znamienkového posunu iba tým, e z¾ava sa prisú-vajú vdy nuly.

Ukáeme si aplikáciu všetkých troch operátorov napraktickom príklade:

int b = 0xCAFEBABE;System.out.println("b << 3 = " + (b << 3));System.out.println("b >> 3 = " + (b >> 3));System.out.println("b >>> 3 = " + (b >>> 3));

Po spustení príkladu dostaneme tri hodnoty, ktoré po pre-vode do šestnástkovej sústavy budú po rade 0x57F5D5F0,0xF95FD757 a 0x195FD757. Prepis týchto hodnôt v binár-nom tvare nás presvedèí o tom, e sa bity pôvodnej hod-

noty 0xCAFEBABE skutoène posunuli o tri pozície do¾ava èidoprava. Ako tie vidíme, operátor >> zachoval zápornéznamienko pôvodného èísla, zatia¾ èo operátor >>> vrá-til kladné èíslo (s nulovým najvyšším bitom).

Pozorný èitate¾ si isto uvedomil, e zmena pozície jed-notlivých bitov má na svedomí zmenu príslušného expo-nentu pri prevode celého èísla do a z dvojkovej sústavy.Skutoène, posun v¾avo o n bitov je totoný s násobenímèísla hodnotou 2n. Naproti tomu znamienkový posunvpravo o n bitov zodpovedá celoèíselnému deleniu hod-notou 2n. Neznamienkový posun vpravo je ekvivalentnýdeleniu mocninou dvojky len pre kladné èísla.

V súvislosti s operátormi bitového posunu treba spo-menú fakt, e posúvané èísla sú vnútorne konvertovanéna jeden z typov int alebo long (pod¾a rozsahu), take

výsledkom posunu premennej typu byte, obsahujúcej hod-notu 0xFF, v¾avo o štyri bity nebude oèakávaná hodnota0xF0, ale hodnota 0x00000FF0 typu int (v prípade, epotrebujeme výsledok šírky typu byte, musíme ho orezapomocou operátora &). S oh¾adom na šírku typov int along sa z pravého operandu, vyjadrujúceho „vzdialenos“posunu, uvauje len spodných pä, resp. šes bitov.

Podmienkový operátor ?:Ïalší javovský operátor ?: bude dobre známy èitate¾oviznalému C++. Na rozdiel od doteraz prebraných operá-torov je operátor ?: ternárny, pracuje s tromi operandmi.Asociuje sa sprava do¾ava, výraz a?b:c?d:e sa pretovyhodnotí ako a?b:(c?d:e).

Sémantika operátora ?:  je nasledujúca: vyhodnotí saprvý operand, ktorý musí by typu boolean. Týmtoprvým operandom je obyèajne nejaká podmienka. Ak je

hodnota prvého operandu true, vyhodnotí a vráti sadruhý operand, ak false, vyhodnotí a vráti sa tretí ope-rand. Druhý a tretí operand musia by rovnakého typu. Jedôleité vedie, e v závislosti od splnenej èi nesplnenejpodmienky sa vyhodnotí buï druhý operand, alebo tretíoperand, nikdy nie oba naraz.

Príklad pouitia – chceme zisti najväèšiu hodnotuz troch èísel a, b a c:

int a = 123, b = 17, c = −229;int max = a>b ? (a>c ? a : c) : (b>c ? b : c);System.out.println("max(a, b, c) = " + max);

V príklade sa najprv porovnajú hodnoty a a b. Ak a jeväèšie ako b, b u nemôe by maximom. Porovnámepreto a s c a väèšie z oboch vrátime ako maximum. V prí-pade, e a nie je väèšie ako b, musí by maximom jednaz hodnôt b alebo c . Ktorá, to zistíme treou aplikáciouoperátora ?:. V našom prípade bude výsledkom hodnota123, uloená v premennej a. Na zamyslenie dávam dopozornosti, preèo urèenie maxima bude fungova aj v prí-pade, e niektoré dve hodnoty (èi priamo všetky tri) budúzhodné.

Pre ilustráciu vyhodnotenia buï druhého, alebo tretie-ho operandu ?: je tu ešte tento krátky príklad:

int i = 2;System.out.println(i > 0 ? (i = 3) : (i = −5));System.out.println(i < 0 ? (i = −2) : (i = 1));System.out.println(i);

V druhom riadku je podmienka i > 0 splnená, vyhodnotísa výraz i = 3, take premenná i bude obsahova hodno-tu 3. Na obrazovku sa vypíše hodnota výrazu i = 3, èo je,samozrejme, 3. V treom riadku podmienka splnenánebude, vyhodnotí sa výraz i = 1, ktorého hodnota 1 savypíše na obrazovku. Premenná i bude ma na konciprogramu hodnotu 1, o èom nás presvedèí štvrtý riadok.Ani v jednom prípade sa nevyhodnotil výraz priraïujúcipremennej i zápornú hodnotu.

Priraïovacie operátoryPoslednými operátormi, o ktorých si povieme, sú operá-tory priradenia. Skutoène je namieste pouitie mnonéhoèísla, pretoe okrem klasického priraïovacieho operátora=, o ktorom sme dosia¾ akosi mlèky predpokladali, e

 jeho význam je zrejmý, a pod¾a toho sme ho pouívaliv príkladoch, poskytuje Java podobne ako C++ jedenásïalších, zloených priraïovacích operátorov +=, -=, *=,/=, %=, &=, |=, ^=, <<=, >>= a >>>=.

 Jednoduchý priraïovací operátor =  je binárny. Jeho¾avým operandom musí by výraz, ktorý sa vyhodnotí akopremenná (t. j. to, èo v C++ nazývame l-hodnota), pravýoperand predstavuje priraïovanú hodnotu. Ak nie jemoné pravý operand konvertova na typ ¾avého operan-du, dôjde pri preklade, prípadne pri behu programu kchybe. Operátor = sa asociuje sprava do¾ava, preto výraza = b = c sa grupuje ako a = (b = c). Hodnotou pri-raïovacieho výrazu je priraïovaná hodnota, take dopremennej a sa priradí tá istá hodnota ako do premennejb, menovite obsah premennej c. Toto viacnásobné prira-

denie je ostatne známe z C++. Pozor, hodnota priraïo-vacieho výrazu u nie je premennou, zápis (a = b) = c jepreto chybný.

Zloené priraïovacie operátory majú bez výnimkytvar op=, kde op je vdy niektorý z doteraz prebranýchbinárnych operátorov. Sémantika zloených operátorovpriradenia je nasledujúca: výraz E1 op= E2 je ekvivalent-

ný výrazu E1 = E1 op E2. Výsledok E1 op E2 sa pred pri-radením spä do E1 konvertuje na typ E1. Zloené operá-tory sú takisto binárne a asociujú sa rovnako ako jedno-duchý operátor =, ich operandy však musia by primitív-nych typov. Jedinou výnimkou je operátor +=, ktorého¾avý operand môe by typu String, pravý operand v ta-kom prípade môe ma ¾ubovo¾ný typ.

Na pouitie operátora = azda netreba uvádza prí-klad, skôr príde vhod nasledujúca ukáka:

int x = 2;x += 3.14;System.out.println("x = " + x);

Ako sa môeme presvedèi spustením tohto programu,premenná x bude ma po priradení pomocou operátora+= hodnotu 5, pretoe výsledok súètu x + 3.14, èo je5.14, sa prevedie naspä na typ int.

Pri vyhodnocovaní zloených priraïovacích operáto-rov op= sa hodnota ¾avého operandu pred vyhodnote-ním pravého operandu zapamätá, take výsledok budenaozaj súètom pôvodnej hodnoty ¾avej strany s výsled-kom pravej strany priradenia. O tom nás presvedèí tentokrátky príklad:

int d = 11;d *= (d = 3) + (d << 2);System.out.println("d = " + d);

Po priradení bude v premenej d uloená hodnota 165.Preèo? Nu, pôvodná hodnota 11 sa zapamätá. Následnévyhodnotenie pravej strany uloí do d hodnotu 3, ktorúsèíta s hodnotou d << 2, èo je 12. Výsledok, èíslo 15, savynásobí s uloenou hodnotou 11, èím dostaneme koneè-ných 165.

5.èas : Pr íkazyVitajte pri ïalšom pokraèovaní nášho rozprávania o Jave.

V piatej èasti sa dozviete, ako pomocou príkazov jazykavysvetlíme poèítaèu, èo má presne robi pri vykonávanínášho programu. Skôr však, ne zaèneme, treba uzavrieešte tému operátory. Pod¾a môjho pôvodného úmysluk tomu malo dôjs ešte v predošlej èasti, ale vzh¾adom naurèité problémy pri výrobe èasopisu sme po dohodes redakciou štvrtú èas Javy pod lupou o nieèo skrátili.Chýbajúci záver teda dostávate do rúk teraz.

PretypovaniePoslednou témou, ktorá spadá do èasti venovanej operá-torom, je špeciálny typ výrazu, tzv.  pretypovávací výraz . Jeho syntax je jednoduchá – pred výraz, ktorému chcemeexplicitne zmeni typ, napíšeme tento výsledný typ dookrúhlych zátvoriek. V C++, vlastne ešte v C blahej

pamäti, sa tomuto zápisu hovorí aj operátor pretypova-nia. V Jave sa dáva prednos pojmu pretypovávací výraz(cast expression). V praxi sa obyèajne tento výraz pouívapri explicitnom pretypovaní èíselných výrazov èi priexplicitnej zmene typu referenènej premennej, ktorá uka-zuje na nejaký objekt (to ide s oh¾adom na dediènos).Príklad:

 byte b = 0x3C; byte c = (byte)(b << 4);

Ak chceme uloi výsledok posunu premennej b typubyte o štyri bity v¾avo naspä do inej premennej c typubyte, musíme poui explicitné pretypovanie, inak pre-kladaè ohlási chybu „Possible loss of precision“ a prog-ram nepreloí.

Výsledkom pretypovania nikdy nie je premenná, zápisz C++:

(double)x = 1.23;

 je teda chybou. V Jave ostatne takýto zápis pravdepodob-ne nikdy nebudeme potrebova.

10 PC REVUE

JAVA POD LUPOU

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 11/36

Pretypováva mono medzi sebou len niektoré typy,napríklad pokus pretypova primitívny typ na referenènýsa skonèí chybou u poèas prekladu. Niektoré pretypova-nia uspejú za kadých okolností (napr. pretypovaniepotomka na predka v objektovej hierarchii tried), správ-nos iných treba overi a za behu programu.

Operátor Význam Asociativita

+ + inkrementácia (postfix) –

– – dekrementácia (postfix)

+ + inkrementácia (prefix) P ® ¼

– – dekrementácia (prefix)

+ unárne plus

– unárne mínus

~ bitová negácia

! logická negácia

(typ) pretypovanie

* násobenie ¼ ® P

 / delenie

% zvyšok po delení  

+ sèítanie ¼ ® P

– odèítanie

<< bitový posun v¾avo ¼ ® P

>> bitový posun vpravo so znam.

>>> bitový posun vpravo bez znam.

< menší ¼ ® P

<= menší alebo rovný

> väèší  

>= väèší alebo rovný

instanceof objekt daného typu

= = rovný ¼ ® P

! = nerovný

& bitový logický súèin ¼ ® P

I bitový logický súèet

^ bitový exkluzívny logický súèet

& & logický súèin ¼ ® P

I I logický súèet

? : podmienené vyhodnotenie P ® ¼

= priradenie P ® ¼

op = zloené priradenie

Priorita operátorovAby bolo rozprávanie o operátoroch úplné, treba ešteuvies poradie, v ktorom sa budú vyhodnocova operáto-ry vo výraze, ktorý neobsahuje zátvorky. Jednotlivéoperátory toti majú rôznu prioritu a klasickým spôso-bom z¾ava doprava sa budú vyhodnocova len operátorys rovnakou prioritou. Zoznam operátorov zoradený pod¾aich klesajúcich priorít je v tabu¾ke. Najvyššiu prioritu má,samozrejme, explicitné uzátvorkovanie príslušných èastívýrazu. Zátvorky sa odporúèa poui vdy, keï by mohlodôjs k omylu èi zmätku pri riešení poradia vyhodnoco-

vania (samozrejme, omylu zo strany programátora, poèí-taè stanovené poradie vdy dodrí).

Krátka rekapituláciaZhròme si teraz v krátkosti, èo sme dosia¾ prebrali.Vieme, e Java stavia na princípoch objektovo orientova-ného programovania. Všetok kód v Jave je organizovanýdo tried, èo sú v princípe šablóny na tvorbu objektov.Kadý existujúci objekt v programe je inštanciou nejakejtriedy. Objekty medzi sebou komunikujú pomocou zasie-lania správ, èo sa zo syntaktického h¾adiska realizujevolaním metód. Metódy sú ekvivalentmi céplusplusov-ských èlenských funkcií tried. Okrem metód, ktoré opisu- jú správanie objektov, nájdeme v triedach èlenské pre-menné, v ktorých je uloený stav objektov. Na úrovni

zdrojového kódu je trieda syntaktickou konštrukciou,ktorá obsahuje opis èlenských premenných a metód.Tomuto opisu inak hovoríme deklarácia. Deklarova vovšeobecnosti treba všetky premenné, ktoré jednotlivéobjekty budú pouíva, èo okrem èlenských premennýchpredpokladá aj lokálne premenné, pouívané pri vykoná-vaní kódu metód. Pri deklarácii premennej je nevyhnutné

uvies jej typ a názov a prípadne aj inicializaènú hodno-tu. Deklarácia metódy oznamuje prekladaèu okrem názvumetódy poèet a typ jej argumentov a typ návratovej hod-noty. Metódy, pochopite¾ne, nemusia ma argumenty anivraca nijakú konkrétnu hodnotu. Èo sa týka typov úda- jov, s ktorými program pracuje, mono ich rozdeli naprimitívne a referenèné. Prvá mnoina typov zahàòa èí-selné typy (celoèíselné i s desatinnou èiarkou) a logickýtyp. Druhá mnoina predstavuje v zásade štruktúrované

typy, menovite objekty (inštancie tried) a polia. Špeciál-nym referenèným typom sú rozhrania. Spôsob spracova-nia údajov v programe sa vyjadruje spôsobom takmermatematickým, pomocou výrazov. Kadý výraz je tvore-ný kombináciou operátorov a ich operandov. Operátorysú symboly vyjadrujúce poadovaný druh operácie, ktorútreba vykona na operandoch. Výsledkom vyhodnoteniavýrazu je vdy nejaká hodnota. Jednotlivé operátory mo-no roztriedi do skupín pod¾a priority vyhodnocovania.

Intermezzo: praktický príkladDos bolo teórie, ukáeme si teraz krátky, ale praktickýpríklad, ktorým bude program na výpoèet koreòov kvad-ratickej rovnice. Aby bol program reálne pouite¾ný,budeme chcie vypoèíta korene aj v prípade, e riešeniebude lea mimo mnoiny reálnych èísel, v komplexnejoblasti. Bohuia¾, dosia¾ sme nehovorili o podmienenomvykonávaní príkazov, preto prosím èitate¾ov o prepáèe-nie, e v programe nájdu zatia¾ neznámy príkaz if . Jehopouitie je však pomerne zrozumite¾né a okrem tohoblišie informácie sa nachádzajú o nieko¾ko odsekovïalej.

Take tu je program (výnimoène kompletný):

import java.io.*;

class Quadratic{

public static void main(String[] args) throwsIOException

{BufferedReader in =

new BufferedReader(new InputStreamReader(System.in));

double a, b, c;

System.out.print("a = ");a = Double.valueOf(in.readLine()).doubleValue();System.out.print("b = "); b = Double.valueOf(in.readLine()).doubleValue();System.out.print("c = ");c = Double.valueOf(in.readLine()).doubleValue();

double D = discr(a, b, c);

if (D > 0){

System.out.println("\nTwo roots:");System.out.println(" x1 = " + ((−b + Math.sqrt(D))

 / 2 / a));System.out.println(" x2 = " + ((−b − Math.sqrt(D)) /

2 / a));}else if (D == 0){

System.out.println("\nOne double root:");System.out.println(" x = " + (−b / 2 / a));

}else{

System.out.println("\nTwo complex roots:");System.out.println(" x1 = " + (−b / 2 / a) +

" + " + (Math.sqrt(−D) / 2 / a) + "i");System.out.println(" x2 = " + (−b / 2 / a) +

" − " + (Math.sqrt(−D) / 2 / a) + "i");}

}

private static double discr(double a, double b, double c){

return b * b − 4 * a * c;}

}

Zdrojový text treba, samozrejme, prepísa do súboruQuadratic.java. Ak program preloíte a spustíte, vypýta

si od vás tri koeficienty kvadratickej rovnice a, b a c.S oh¾adom na jednoduchos sa nikde nekontroluje, èizadáte kvadratický koeficient a nenulový (program v tomprípade poskytne kuriózne výsledky – presvedète sasami). Takisto nie je nijako ošetrené zadanie neèíselnýchhodnôt. Spôsob zadávania vstupu vyzerá ve¾mi kompli-kovane, ale zatia¾ ho èitate¾ bude musie akceptova bezvysvetlenia.

Na výpoèet diskriminantu je v triede Quadratic zave-

dená súkromná metóda discr(). Spoèítaná hodnota dis-kriminantu sa testuje voèi nule. V prípade, e je diskri-minant kladný, program vypoèíta a vypíše dva reálnekorene, nulový diskriminant znamená jeden dvojnásobnýkoreò a koneène záporná hodnota diskriminantu spôsobívýpoèet dvoch komplexných koreòov.

Verím, e sa na mòa nebude ani jeden èitate¾ hnevaza pouitie anglických textov v programe. Angliètina, akolingua franca poèítaèového sveta (internet nevynímajúc),dnes toti patrí medzi nevyhnutné, i keï rozhodne niepostaèujúce znalosti úspešného programátora.

Hor' sa na príkazyAko sme u nieko¾kokrát uviedli, beiaci program v Javesi mono predstavi ako mnoinu vytvorených objektov,ktoré medzi sebou komunikujú prostredníctvom správ.Na syntaktickej úrovni je poslanie správy realizované akozavolanie konkrétnej metódy konkrétneho objektu. Akovšak virtuálny poèítaè vie, èo má robi pri vyvolaní danejmetódy? Nu, povie mu to obsah tela metódy, ktoré, akosme videli, je uzavreté do zloených zátvoriek ({}). Telokadej metódy je tvorené postupnosou príkazov.

Ak sú teda stavebnými jednotkami programu objektyso svojimi atribútmi a metódami, mono poveda, e sta-vebnými jednotkami jednotlivých metód sú príkazy.Kadý príkaz opisuje jeden malý krok algoritmu, ktorýdaná metóda realizuje. V uvedenom príklade sme malimetódu discr(), ktorá obsahovala jediný príkaz na výpo-èet hodnoty diskriminantu. Mohli sme, pravda, tentovýpoèet rozdeli do viacerých krokov, a teda do viacerýchpríkazov, ale bolo by to zbytoèné.

Kadá metóda obsahuje iaden, jeden èi viacero príka-zov, ktoré sú navzájom oddelené bodkoèiarkou. Áno,metóda môe obsahova aj nulový poèet príkazov – taká-to prázdna metóda síce nerobí niè uitoèné, ale môeslúi ako akýsi zástupca (angl. placeholder, ktorý doslo-va „drí miesto“) do doby, kým potrebné príkazy do jejtela doplníme (niè neobyèajné pri vývoji väèších progra-mov).

Deklaraèné a výrazové príkazyPrvé dva typy príkazov u dobre poznáte, ani o tomneviete. Kadá deklarácia lokálnej premennej je príka-zom. V tele metódy, samozrejme, nemono deklarova

niè iné ako lokálne premenné (a takisto lokálne triedy, aleo tom ešte budeme hovori). Zoberme si príklad:

double a, b, c;

Tento zápis je príkazom, ktorého úèinok je zrejmý:prekladaè odteraz a do skonèenia príslušného rozsahuplatnosti bude identifikátory a, b a c povaova za pre-menné typu double a pod¾a toho bude s nimi aj narába.

Iným typom príkazu je výrazový príkaz. Takmer kadývýraz, ktorý je správne zapísaný pod¾a syntaktických pra-vidiel Javy, môeme poui ako samostatný príkaz.Slovko takmer je namieste – Java toti na rozdiel od C++povo¾uje ako príkazy poui len výrazy, ktoré spôsobujúnejaký trvalý efekt. Medzi ne patrí volanie metódy(mono zavola aj metódu, ktorá „niè nemení“, ako napr.

naša metóda discr(), ktorá len vráti vypoèítanú hodnotu),priraïovací výraz èi výrazy s operátormi ++ a --. Pripokuse poui ako príkaz výraz, ktorý iba vracia hodno-tu, prekladaè ohlási chybu. Tu je príklad výrazového prí-kazu, ktorý má úèinok – zmení obsah premennej x:

x *= (x − 1);

PC REVUE 11

JAVA POD LUPOU

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 12/36

A pre úplnos je tu aj chybný výrazový príkaz, ktorý„niè nerobí“:

x * (x − 1); // CHYBA!

Výsledná hodnota výrazu pouitého vo výrazovom príkazesa ignoruje.

Podmienený príkaz if S týmto príkazom sme sa u stretli v príklade o nieko¾koodsekov vyššie. Príkaz if  slúi na vyjadrenie podmiene-ného vykonávania urèitej èasti programu v závislosti odsplnenia èi nesplnenia zadanej podmienky. Jeho syntax jenasledujúca:

if ( podmienka )príkaz

Príkaz if má ešte jeden moný zápis:

if ( podmienka )

príkaz1

else

príkaz2

V prvom, kratšom tvare sa príkaz vykoná vtedy a len

vtedy, keï výraz podmienka bude ma hodnotu true. Narozdiel od C++ musí by podmienkový výraz typu boo-lean, inak dôjde k chybe pri preklade. V prípade, e pod-mienka nie je splnená, teda výraz má hodnotu false, prí-kaz sa preskoèí. Druhý zápis umoòuje vybra z dvojicepríkazov pod¾a toho, èi je podmienka pravdivá alebo nie.Ak bude výsledkom výrazu podmienka hodnota true,vykoná sa príkaz1, ak sa podmienka vyhodnotí na false,vykoná sa príkaz2.

Bolo by dos nešikovné, keby sme v rámci príkazu if mohli skutoène poui iba jeden príkaz, vykonávaný vzávislosti od splnenia èi nesplnenia podmienky. Preto jev Jave podobne ako v C++ moné na mieste takmer ka-dého príkazu poui tzv. zloený príkaz, resp. blok príka-zov. Takýto blok vytvoríme jednoducho: uzavrieme po-

adované príkazy do zloených zátvoriek. Za zloenýmpríkazom na rozdiel od jednoduchého nepíšeme nikdybodkoèiarku.

I keï pouitie príkazu if je zrejmé z programu na rieše-nie kvadratickej rovnice, ukáeme si ešte nejaký príklad:

if (a == 0)System.out.println("a is zero");

elseSystem.out.println("a is non−zero");

Takýto úsek kódu vypíše, èi obsah premennej a je nulovýalebo nenulový. Príslušné vetvy príkazu if obsahujú lenpo jednom príkaze, preto sú zloené zátvorky zbytoèné.Ak však budeme ma nasledujúci príklad:

if (a != 0){ b = 5 / a;System.out.println("5 / a = " + b);

}else

System.out.println("cannot divide");

zloené zátvorky okolo dvoch príkazov v „true“ vetve prí-kazu if sú nevyhnutné.

V súvislosti s príkazom if treba spomenú jeden z naj-známejších zádrhov v programovacích jazykoch. Obsa-hom kladnej vetvy príkazu if môe by opä príkaz if . Akovšak vyrieši nasledujúcu situáciu?

if (x != 0)if (y != 0)

z = 1 / (x * y);else

z = 1 / x;

Patrí èas else prvému èi druhému príkazu if ? V tomtopríklade odsadenie kódu nasvedèuje druhej monosti. Sku-toène, prakticky vo všetkých programovacích jazykoch,

ktorých sa tento problém týka, existuje pravidlo, pod¾aktorého èas else prislúcha vdy najblišiemu neuzavre-tému príkazu if , v našom prípade druhému, vnorenému.Pozor teda, ak chceme ma èas else len pri vonkajšom if ,musíme poui zloené zátvorky:

if (x != 0){

if (y != 0)z = 1 / (x * y);

}else

z = 1;

Mimochodom, v ukákovom programe na riešenie kvad-ratickej rovnice je pouité iné zdruovanie príkazov if ,ktoré nie sú vnorené jeden do druhého, ale sú takpove-diac zreazené – ak nie je splnená jedna podmienka, tes-tuje sa druhá, prípadne tretia a ïalšie. Ak by sme chcelidodriava pravidlá pre „pekné“ formátovanie zdrojo-vého textu, rýchlo by zdrojový kód zaèal preteka cezpravý okraj okna editora. V praxi teda obyèajne namiestozápisu:

if (D > 0){

 // ...}else

if (D == 0){ // ...

}else

if (D < 0){ // ...

}

pouijeme úspornejší zápis:

if (D > 0){ // ...

}else if (D == 0){ // ...

}else if (D < 0){ // ...

}

 Poznámka: ak je èitate¾ zvyknutý z C++ testova ne-nulovos èi nulovos premennej (napr. x) takto:

if (x) { ... }

resp.

if (!x) { ... }

má v Jave smolu, takéto zápisy sú chybné. Podmienkovévýrazy toti musia by typu boolean a treba poui tvary:

if (x != 0) { ... }

prípadne

if (x == 0) { ... }

Podmienený príkaz switchÏalším príkazom, pomocou ktorého mono vetvi vyko-návanie programu v závislosti od urèitej podmienky, jepríkaz switch. Ako napovedá jeho názov, ide doslovao prepínaè, ktorý vyberie vetvu programu na základehodnoty nejakého výrazu. Takýto kód mono naprogra-mova aj pomocou zreazených príkazov if , ale pripouití príkazu switch ušetríme daèo miesta a ešte k

tomu zabránime viacnásobnému vyhodnocovaniu testo-vaného výrazu (èo oceníme v prípade, e tento výraz mánejaké ved¾ajšie úèinky).

Ako vyzerá príkaz switch? Jeho syntax je nasledujúca:

switch ( výraz ){

case hodnota1 : príkazy

case hodnota 2 :

 príkazy

 // ...

default:

 príkazy}

Pozrime sa na túto schému podrobnejšie. Za k¾úèovýmslovom switch nájdeme v okrúhlych zátvorkách testova-ný výraz. Ten musí ma niektorý z typov char , byte,short alebo int. Za výrazom nasleduje v zloenýchzátvorkách uzavretý blok príkazov. V tomto bloku sa naurèitých miestach vyskytujú tzv. návestia v tvare casehodnota. Jednotlivé hodnoty v návestiach musia byrôzne a kompatibilné s typom výrazu.

Keï program poèas behu dospeje k príkazu switch,urèí hodnotu výrazu a postupne bude preh¾adáva hod-noty uvedené v návestiach v bloku príkazov. Ak nájdezhodu, zaène vykonáva príkazy za nájdeným návestíma do konca tela príkazu switch. V prípade, e ani jednonávestie neobsahuje h¾adanú hodnotu, program pokraèu-

 je príkazmi za návestím default. Toto návestie nie jepovinné, a ak sa v tele príkazu switch nenachádza, prog-ram jednoducho pri neúspešnom h¾adaní zhody príkazswitch preskoèí.

Podobne ako v C++ sa v okamihu nájdenia zhodyïalšie návestia ignorujú a program takpovediac „prepa-dáva“ cez jednotlivé návestiami oddelené úseky príkazov,a kým dospeje na koniec príkazu switch. To ilustrujenasledujúci príklad:

class OneTwo{

public static void main(String[] args){

show(3);show(2);show(1);

}static void show(int n){

switch (n){case 1:

System.out.print("one ");case 2:

System.out.print("two ");default:

System.out.print("other");}System.out.println("");

}}

Tento program po spustení vypíše riadky:

other two otherone two other

pretoe po odskoku na návestie case 1, resp. case 2, a vy-písaní príslušného textu program jednoducho pokraèujeïalšími príkazmi v tele switch. Ak tomu chceme zabráni,treba poui iný príkaz break, ktorý v tele príkazu switchspôsobí, e program z tohto tela vyskoèí a bude pokraèo-va prvým príkazom za celým blokom switch.

Upravená metóda show() bude potom vyzera takto:

static void show(int n){

switch (n){case 1:

System.out.print("one"); break;

case 2:System.out.print("two"); break;

default:System.out.print("other");

12 PC REVUE

JAVA POD LUPOU

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 13/36

}System.out.println("");

}

S takouto verziou show() u program vypíše správnyvýstup:

other twoone

Príkaz cyklu whileDva predchádzajúce príkazy, if a switch, patria medzi prí-kazy selekcie, resp. alternatívy, takisto sa im hovorí pod-mienkové príkazy. Druhý okruh príkazov, na ktorých je za-loená teória štruktúrovaného programovania, sú príkazycyklu.

Na realizáciu jednoduchého cyklu s testovaním pod-mienky na zaèiatku slúi príkaz while. Syntax tohto prí-kazu je:

 while ( podmienka )

 príkaz

Výraz podmienka musí by podobne ako v príkaze if typuboolean, iný typ prekladaè odmietne. Na mieste príkazumôe stá aj zloený príkaz, teda blok príkazov, uzavretý

v zloených zátvorkách.Príkaz  while sa vykonáva týmto spôsobom: najprv sa

vyhodnotí podmienkový výraz. Ak je jeho hodnota pravdivá,teda true, vykoná sa príkaz a opätovne sa riadenie progra-mu vráti akoby pred príkaz  while. Ak bude hodnota pod-mienky nepravdivá, cyklus  while sa konèí, príkaz sa ïalejvykonáva nebude. Treba si uvedomi, e ak bude u nazaèiatku cyklu podmienka nesplnená, telo cyklu sa nevyko-ná ani raz.

Slovo „while“ v angliètine znamená „kým, pokia¾“ apod¾a toho sa aj cyklus  while správa: vykonáva príkaz,kým je splnená urèitá podmienka. Podmienka sa testujepred vykonaním tela cyklu.

Ukáme si príklad na tento cyklus. Chceme nájs naj-menšieho spoloèného delite¾a dvoch èísel uloených v

premenných a a b. Pouijeme známy Euklidov algoritmus: while (a != b){

if (a > b)a = a − b;

else b = b − a;

}

Cyklus bude „cykli“ dovtedy, kým budú hodnoty pre-menných a a b rôzne. Po skonèení cyklu bude v obochpremenných a aj b ich najmenší spoloèný delite¾ (uko-nèovacou podmienkou je rovnos premenných a a b).Program, pochopite¾ne, nefunguje pre záporné hodnoty.

V cykle  while, podobne ako v príkaze switch, môemepoui príkaz break. V tele cyklu však tento príkaz spôsobíokamité prerušenie vykonávania cyklu a vyskoèenie prog-ramu za koniec tohto cyklu. Jedným z èastých príkladovpouitia je cyklus, v ktorom testujeme podmienku niekde„uprostred“:

 while (true){

a++;if (a > 100) break;

 b−−;}

(Neh¾adajte v tomto úseku kódu hlbší zmysel, nie je tam.)Za povšimnutie stojí, e ako podmienku cyklu while smeuviedli literál true. Takáto podmienka bude vdy splne-

ná, a preto by sa cyklus nikdy neskonèil, neby toho, ev urèitom momente (v tomto prípade, keï premennáa prekroèí stovku) príkazom break cyklus prerušíme.

Príkaz cyklu doPri príkaze  while sa testuje iteraèná podmienka nazaèiatku cyklu. Môe sa však sta, e budeme potrebova

túto podmienku testova a na konci cyklu, pretoenapríklad jej obsah závisí od toho, èo sa v tele cyklu vyko-nalo. Pre tento variant máme v Jave k dispozícii príkaz dos nasledujúcou syntaxou:

do

 príkaz

 while ( podmienka );

Podmienka musí by opä typu boolean a príkaz môeby zloený.

Pri realizácii cyklu do sa vykoná príkaz a otestuje sahodnota podmienkového výrazu. Ak je true, cyklus sabude opakova, ak false, program pokraèuje ïalším prí-kazom za cyklom do. Na rozdiel od cyklu  while sa telocyklu do vykoná vdy aspoò raz. Na predèasné opustenietela cyklu môeme poui u spomínaný príkaz break.

Príklad cyklu do:

double d;do {

d = Math.random();} while (d >= 0.1);

Kninièná metóda Math.random() vracia náhodné èíslo

z intervalu <0; 1>. Cyklus sa teda bude opakova, kýmtáto metóda nevygeneruje èíslo menšie ako 0,1.Výsledkom bude náhodné oneskorenie programu (na sú-èasných poèítaèoch, samozrejme, neve¾mi badate¾né).

Dokonèenie nabudúceV budúcom pokraèovaní tému príkazov uzavrieme uni-verzálnym príkazom cyklu for  a pomocnými príkazmibreak a continue.

6.èas : P r í kazy (dokonèenie)

Príkaz cyklu for Tretí príkaz cyklu, príkaz for , je znaène univerzálny. Syn-

tax má trošku zloitejšiu:

for ( init ; podmienka ; iterácia )

 príkaz

Všimnime si podrobnejšie obsah zátvorky. Skladá saz troch èastí oddelených bodkoèiarkou. Prvá èas, nazva-ná init, predstavuje jeden alebo viac výrazových príkazov(ak ich je viac, oddelíme ich èiarkou). Táto èas sa vykonápred zaèiatkom cyklu for – môeme poveda, e to je ini-cializaèná èas. Dávame do nej obyèajne inicializáciu ria-diacich premenných cyklu.

Druhá èas, výraz podmienka, má podobný významako v cykle while. Teda telo cyklu for sa bude vykonávadovtedy, kým bude táto podmienka splnená. Len èo sapodmienka stane nepravdivou, cyklus sa konèí. Podmien-kový výraz sa vyhodnocuje pred telom cyklu.

Tretia èas, oznaèená ako iterácia, obsahuje výrazy,ktoré sa majú vykona po kadom prechode cyklom.Obyèajne sa tu pod¾a potrieb menia riadiace premenné.Telo cyklu je tvorené príkazom, ktorý opätovne môe byaj zloený.

Pouitie príkazu for si ukáeme na úseku programu,ktorý spoèíta prvých N prirodzených èísel, kde N je neja-ké vopred známe èíslo, uloené v premennej N:

int N = 100;int i, sum = 0;for (i = 1; i <= N; i++)

sum += i;System.out.println(sum);

Spoèítavané èísla z intervalu <1; 100> uchovávamev premennej i. Táto premenná je tzv. riadiacou premen-nou cyklu, èo sa dá preloi aj tak, e obsah premenneji sa vhodne mení pri kadom prechode telom cyklu.Inicializaèná èas príkazu for , teda príkaz i = 1, nastaví

hodnotu premennej i na prvú spoèítavanú hodnotu, tedana jednotku. Podmienka cyklu znie: i <= N. Cyklus sateda bude opakova dovtedy, kým premenná i nepresiah-ne koncovú hodnotu N. V tele cyklu vykonávame triviál-nu operáciu, pripoèítanie aktuálnej hodnoty i k premen-nej sum, kde uchovávame priebený súèet. Túto premen-nú nesmieme zabudnú na zaèiatku vynulova. Koneènepravidelné zvyšovanie hodnoty i o jednu zabezpeèí tretívýraz, i++.

Nikde nie je napísané, e riadiacu premennú cyklu mu-síme v tele cyklu poui. Keby sme chceli vypísa desa-krát hoci reazec „Java pod lupou“ (síce neviem naèo, aleako príklad to postaèí), napíšeme cyklus:

for (int i = 0; i < 10; i++)System.out.println("Java pod lupou");

Pozorný èitate¾ si isto všimne, e v inicializaènej èasticyklu sa nachádza deklaraèný príkaz int i = 0. To je dovo-lené, ale pozor, takto deklarovaná premenná i je lokálnapre daný cyklus a po jeho skonèení zaniká. Okrem tohonesmieme v inicializácii kombinova deklaraèné a výra-zové príkazy. Inak by toti mohlo dôjs k dvojznaènosti,napr. pri takomto cykle:

for (int i = 0, j = 10; ... )kde sú v inicializaènej èasti dva príkazy, by nebolo jasné,èi druhý príkaz  j = 10 priraïuje hodnotu 10 existujúcejpremennej  j alebo deklaruje novú premennú j typu int anastavuje ju na hodnotu 10. Z tohto dôvodu platí pravid-lo, e ak je prvý príkaz deklaraèný, za deklaraèné sa po-vaujú aj ostatné.

Riadiacu premennú cyklu nemusíme nevyhnutne prikadom prechode cyklom inkrementova. Dajme tomu,e potrebujeme vypísa mocniny dvojky od 20 po 210. Niè¾ahšie:

for (int i = 1; i <= 1024; i *= 2)System.out.println(i);

Premenná i sa po kadej iterácii cyklu zdvojnásobí pomo-

cou výrazu i *= 2.Ak sa zamyslíme nad spôsobom vykonávania cyklu

for , dôjdeme k záveru, e ho môeme teoreticky prepísatakýmto spôsobom:

init ;

 while ( podmienka )

{

 príkaz ;

iterácia ;

}

Tento prepis platí okrem jednej malej výnimky, o ktorejsi povieme v ïalšom odseku. K príkazu for zostáva u lendoda, e ak chceme cyklus ukonèi predèasne, pouijeme

známy príkaz break.Príkazy break a continuePosledné dva príkazy, o ktorých bude reè, sú príkazybreak a continue. Prvý z nich, break, sme u nieko¾ko-krát spomínali. Tento príkaz mono poui buï vo vetvia-com príkaze switch na okamité vyskoèenie von z bloku,alebo v príkazoch cyklu  while, do a for na okamité uko-nèenie cyklu. Inde jeho pouitie vedie k chybe pri preklade.

Príkaz break však mono poui aj s jedným argu-mentom, ktorým je tzv. návestie. O návestiach sme sa ubavili v súvislosti s príkazom switch. V Jave však môeby kadý zloený príkaz, resp. kadý z príkazov switch, while, do, for , ktoré obsahujú zloený príkaz, oznaèenýpomocou návestia. Návestím je obyèajný reazec znakov(platia rovnaké pravidlá ako pre názvy premenných) uko-nèený dvojbodkou, ktorý umiestnime pred príslušný zlo-ený príkaz. Výskyt príkazu break s návestím potom spô-sobí okamité vyskoèenie zo zloeného príkazu, ktorý jetýmto návestím oznaèený. Je zrejmé, e sa tento breakmusí v danom zloenom príkaze nachádza.

Typicky sa príkaz break s návestím pouíva na vysko-

PC REVUE 13

JAVA POD LUPOU

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 14/36

èenie z vnoreného cyklu, èo sa v C++ s ob¾ubou robípomocou príkazu goto. Tento azda najpolemizovanejšípríkaz nepodmieneného skoku v Jave toti nenájdeme.Ukáme si príklad:

outer:for (int i = 0; i < 10; i++){

for (int j = 0; j < 10; j++){

if (i == j) break;if (i == 8) break outer;

System.out.print(i + "−" + j + " ");}System.out.println("");

}

V príklade máme dva vnorené cykly, pomocou ktorýchprechádzame pomyselnú súradnicovú mrieku, súradni-ce máme v premenných i a j. V kadom prechode vnútor-ným cyklom vypíšeme súradnice aktuálneho bodumrieky na obrazovku. V prípade, e sa nachádzame nadiagonále, kde sú obe súradnice rovnaké (i == j), tentoa nasledujúce body na aktuálnom riadku „preskoèíme“.Okrem toho, keï sa dostaneme na predposledný riadok,pre ktorý bude v i hodnota 8, vyskoèíme pomocou breakouter z celého cyklu, a teda body na riadkoch so súradni-cami 8 a 9 vôbec nevypíšeme. Všetko bude ove¾a jasnejšiepo spustení programu.

Druhý príkaz, continue, sa pouíva iba v príkazochcyklu, teda while, do a for . Pokia¾ ho pouijeme bez ná-vestia, spôsobí okamité ukonèenie práve prebiehajúcejiterácie cyklu a skok na pomyselný zaèiatok cyklu, èo spô-sobí nové vyhodnotenie cyklovacej podmienky a pod¾a jejvýsledku prípadné pokraèovanie èi nepokraèovanie vcykle. V príkaze for sa pred týmto opätovným testovanímpodmienky ešte vykonajú všetky výrazy tretej, iteraènejèasti (pozri vyššie). To je ten spomínaný malý rozdielmedzi for a jeho náhradou pomocou while.

Aj príkaz continue mono poui s návestím, význam je analogický: ukonèí sa práve prebiehajúca iterácia tohocyklu, ku ktorému dané návestie patrí. Modifikujme pred-chádzajúci príklad tak, e príkazy break nahradíme prí-kazmi continue:

outer:for (int i = 0; i < 10; i++){

for (int j = 0; j < 10; j++){

if (i == j)continue;

if (i == 8)continue outer;

System.out.print(i + "−" + j + " ");}System.out.println("");

}

Tentoraz sa z výpisu vynechajú iba body leiace na dia-gonále a celý riadok so súradnicou 8.

Prázdny príkazPríkazov v Jave nájdeme ešte o nieèo viac, ale tie savzahujú buï na výnimky (try, finally, catch, throw),alebo na synchronizáciu v multithreadovom prostredí(synchronized), take si o nich povieme a neskôr. Na zá-ver sa patrí spomenú tzv. prázdny príkaz, ktorým je jed-noducho „niè“ nasledované bodkoèiarkou:

;

Prázdny príkaz mono poui napríklad ako telo cyklu

for , ktorého celú náplò sme vyjadrili buï v podmienko-vom, alebo v i teraènom výraze.

Zahráme sa na kombajnyA v budúcom pokraèovaní seriálu sa vrhneme na poliaa prácu s nimi. Teším sa na stretnutie opä o mesiac.

7.èas : Pol ia

Polia v Jave sú samostatnou kapitolou. Na jednej straneich nemono zaradi medzi primitívne typy, pretoe usvojou podstatou patria medzi agregované údajové typy.Na druhej strane nejde ani o plnohodnotné objekty, takako o nich bola reè v krátkom úvode do OOP, predovšet-kým preto, lebo polia nie sú tvorené na základe vopred

zadanej šablóny (ktorej sa hovorí trieda).Skôr ne sa dostaneme k opisu polí v Jave, zopakujmepre menej zdatných, èo je vôbec to pole. Take najprvuèená definícia: pole je postupnos prvkov rovnakéhotypu. Dôleité je slovko „rovnakého“. Typickou situáciou,na ktorej mono ukáza opodstatnenos existencie polí, je nutnos vykona nejakú operáciu na netriviálnom mnost-ve údajov. Mohli by sme síce pre kadý údaj vytvorisamostatnú premennú, ale jednak by sme museli zara-dom pre tieto premenné vymýš¾a mená (a kadé iné!), jednak by sme zamýš¾anú operáciu museli do programuzadáva znova a znova, hoci zakadým nad inou premen-nou. Èo je, pochopite¾ne, neúnosné a vo väèšine prípadovprakticky nerealizovate¾né riešenie.

Zavedenie po¾a oba problémy vyrieši šmahom ruky.

Prvky po¾a sú zastrešené pod jedným názvom – názvompo¾a – a prístup k nim realizujeme prostredníctvom tzv.indexu (ktorým je v Jave celé èíslo). No a generova po-stupne celé èísla v poadovanom rozsahu vieme – po-uijeme cyklus, teda napríklad príkaz for. V tele cykluvyjadríme poadovanú operáciu nad i-tym prvkom po¾aa premennú i jednoducho necháme prebehnú cez všetkyindexy po¾a.

Vytvorenie po¾aSkôr ne pole zaèneme pouíva, treba ho nejakým spô-sobom vytvori. Podobne ako pri primitívnych typochmusíme najprv deklarova premennú, pomocou ktorejbudeme na pole odkazova. Èitate¾ si isto spomenie, ev deklarácii premennej je nevyhnutné zada okrem názvu

aj jej typ. Ten pri poliach vytvoríme jednoducho: prida-ním hranatých zátvoriek [] za niektorý z primitívnychtypov, ktorý sme si vybrali ako typ prvkov po¾a. Ak chce-me napríklad pole celých èísel, bude deklarácia vyzeratakto:

int[] ai;

Od tejto chvíle je ai premennou typu „pole prvkov typuint“. Nanešastie to nie je všetko. Polia v Jave toti na roz-diel hoci od C++ nikdy nie sú statické a vdy ich trebavytvori dynamicky, za behu programu. V jednej z prvýchèastí seriálu sme hovorili o rozdiele medzi primitívnymitypmi a referenènými typmi. Polia leia niekde na pome-dzí, ale blišie majú k referenèným typom; dôleité

v tomto momente je, e premenná typu pole (teda aj našapremenná ai) obsahuje v skutoènosti len odkaz, referen-ciu na skutoèný objekt po¾a. A tento objekt sme zatia¾ nevytvorili. Premenná ai zatia¾ obsahuje len špeciálnuhodnotu null, informujúcu o tom, e ai neukazuje nikam.

Samotný objekt, obsahujúci jednotlivé prvky po¾a,môeme vytvori dvojakým spôsobom. Prvý je zaloenýna jednoduchom vymenovaní hodnôt všetkých prvkov;tieto hodnoty oddelíme èiarkami, uzavrieme do zloe-ných zátvoriek a doplníme do deklarácie za operátor =:

int[] ai = { 11, 22, 33, 44 };

Týmto riadkom sme naraz deklarovali premennú ai typu„pole celých èísel“, vytvorili objekt "pole štyroch celých

èísel" s uvedenými hodnotami a do premennej ai smeuloili odkaz na tento novovytvorený objekt. Za povšim-nutie stojí, e premenná ai nijako vopred nevie, aký budepoèet prvkov po¾a, na ktoré bude ukazova. To je ve¾mipozitívna vlastnos, ktorá programátorovi ušetrí kôpkustarostí.

Druhý spôsob vytvorenia objektu po¾a je blízky C++.Pouijeme k¾úèové slovo new, za ktoré doplníme typ po¾apod¾a uvedeného vzoru, tentoraz však s doplneným poè-tom prvkov medzi hranatými zátvorkami. Príklad:

int[] ai = new int[4];

Takto vytvorené pole nie je však nijako inicializovanéa všetky jeho prvky obsahujú implicitné hodnoty, tedanuly. Ak chceme dosta do po¾a nejaké rozumné údaje,spravíme to buï v cykle:

for (int i = 0; i < 4; i++)

ai[i] = i * 11;

alebo pouijeme nasledujúci zápis, ktorý spája vytvore-nie pomocou new s inicializáciou:

int[] ai = new int[] { 11, 22, 33, 44 };

Tentoraz poèet prvkov v hranatých zátvorkách nesmiemeuvies. Na poh¾ad sa celá vec zdá komplikovaná, ale pra-vidlo je jednoduché: ak zadáme zoznam inicializaènýchhodnôt, neuvádzame explicitne poèet prvkov (ten je zrej-mý zo zadaného zoznamu) a naopak.

A teraz si predstavme inú situáciu. Máme deklarovanú

premennú typu pole (teda napríklad premennú ai z nášhopríkladu) a chceme jej priradi odkaz na iné pole, hoci ajs inou dåkou. V Jave nijaký problém, zapíšeme buï:

ai = new int[3];

a pole naplníme v cykle, a lebo pouijeme tvar:

ai = new int[] { 111, 222, 333 };

Pôvodné štvorprvkové pole je od tejto chvíle stratené,zabudnuté a odsúdené na ne¾útostný koniec v paerákugarbage-collectora.

Prístup k prvkom po¾aKeï u máme pole vytvorené, môeme s jeho prvkamipracova. i-ty prvok po¾a ai sprístupníme zápisom:

pi[i]

teda za názov premennej, ktorá odkazuje na dané pole,dáme do hranatých zátvoriek príslušný index. Indexypo¾a, ktoré má N prvkov, sú vdy v rozsahu 0 a N-1. Akby sme zadali index záporný alebo väèší, ne je dåkapo¾a, dôjde poèas behu programu k výnimke. H¾a, akýrozdiel oproti C++! Tam sme mohli prepisova pamä,ako sa nám zapáèilo. U je teraz jasnejšie tvrdenie, e Java je bezpeènejšia ako C++?

Konštanta alebo premenná pouitá ako index musí bytypu int. Môeme, samozrejme, poui aj premenné typubyte, short a char , pretoe tie sa automaticky konvertu-

 jú na typ int; nie je však dovolené indexova polia pomo-cou premenných (a konštánt) typu long.Ukáme si teraz krátky príklad, v ktorom vytvoríme

pole, naplníme ho náhodnými hodnotami a potom spoèí-tame súèet prvkov po¾a a ich aritmetický priemer:

int[] a = new int[20];for (int i = 0; i < a.length; i++){

a[i] = (int)(Math.random() * 100);System.out.print(a[i] + " ");

}int sum = 0;for (int i = 0; i < a.length; i++)

sum += a[i];double avg = (double)sum / a.length;System.out.println("\nSum = " + sum);

System.out.println("Avg = " + avg);

Na generovanie náhodných èísel pouívame metóduMath.random(), ktorá vracia pseudonáhodné èíslo typudouble z intervalu <0; 1). To vynásobíme èíslom 100 avýsledok pretypujeme na int, take kadý prvok po¾a

14 PC REVUE

JAVA POD LUPOU

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 15/36

bude náhodným èíslom z intervalu 0 a 99.V príklade sa vyskytuje ešte jeden nový prvok, a to

výraz a.length. Polia v Jave sú objektmi a objekty, akovieme, obsahujú atribúty. V kadom poli takto mámek dispozícii konštantný atribút length, ktorý udáva poèetprvkov po¾a. Èo viac si môeme ela? Ak posielame poleako argument nejakej funkcii, netreba spolu s ním posie-la jeho dåku, pretoe tú si funkcia zistí sama z posla-ného po¾a!

Viacrozmerné poliaPrvkami polí nemusia by len premenné primitívnehotypu, rovnako dobre môeme deklarova polia objektov.A keï je kadé pole samo osebe takým „skoroobjektom“,preèo by sme nemohli deklarova pole, ktorého prvkamibudú opä polia?

Pojem viacrozmerné polia nie je celkom presný, rov-nako ako nebol celkom presný v C++. Viacrozmernépolia nájdeme v Pascale, ale v C++ alebo v Jave ide vskutoènosti o polia, ktorých prvky sú takisto polia. A prv-kami týchto polí môu by opä polia a tak ïalej, dohåbky, ktorú potrebujeme.

Ukáme si teraz na príklade, ako by sme deklarovali„dvojrozmerné“ pole celých èísel. Potrebujeme deklaro-

va pole prvkov typu „pole celých èísel“. Tento typ upoznáme, je to int[]. A poznáme aj pravidlo, ako vytvorityp po¾a prvkov nejakého typu – pridaním hranatýchzátvoriek. Tak dostaneme výsledný typ int[][]. Príklad dekla-rácie:

int[][] aai;

Takto deklarovaná premenná aai opä neukazuje nikama obsahuje len hodnotu null. Jediné, èo o nej môemepoveda, je, e ak bude na nieèo odkazova, tak to nieèobude pole polí celých èísel. Ak ju chceme spolu s deklará-ciou inicializova, pouijeme napríklad takýto zápis:

int[][] aai = { { 1, 2 }, { 3, 4 } };

(Všimnite si rekurzívnos inicializaèného zoznamu. Ten je tvorený postupnosou inicializaèných hodnôt od-delených èiarkou a uzavretých do zloených zátvoriek.Ak inicializaèná hodnota inicializuje vnorené pole, budesama osebe podobným zoznamom.)

Teraz premenná aai odkazuje na dvojprvkové pole,ktorého kadý prvok je opä dvojprvkové pole celýchèísel. Prvé pole, aai[0], obsahuje prvky aai[0][0] a aai[0][1],druhé pole, aai[1], obsahuje zase prvky aai[1][0] a aai[1][1].V pamäti existujú teda tri polia: prvé pole je to, na ktoréodkazuje premenná aai. Toto pole má dva prvky, ktorýmisú dve premenné aai[0] a aai[1] odkazujúce kadá nasvoje samostatné dvojprvkové pole.

Premennú aai môeme inicializova aj takýmto spôso-bom:

int[][] aai = { null, null };

Tentoraz sa v pamäti vytvorilo iba jediné pole, na ktoréodkazuje premenná aai. Oba jeho prvky majú hodnotunull, a teda neukazujú nikam. Aby sme ich prinútili uka-zova na nejaké reálne objekty polí, musíme ich iniciali-zova explicitne:

aai[0] = new int[] { 1, 2 };aai[1] = new int[] { 3, 4, 5 };

A teraz dávajte dobrý pozor! Zatia¾ èo premenná aai[0]ukazuje podobne ako v predchádzajúcom príklade nadvojprvkové pole obsahujúce hodnoty 1 a 2, premennáaai[1] odkazuje na pole troch prvkov, èísel 3, 4 a 5! Vo

výsledku sme teda dostali dvojrozmerné pole, ktoréhodruhý rozmer nie je pevne daný, ale sa mení pod¾a inde-xu prvej úrovne. (Keï sa to tak vezme, podobnú konš-trukciu mono vytvori aj v C++, ale trochu menej ele-gantne a mono aj menej preh¾adne. A okrem toho javov-ské runtime prostredie automaticky kontroluje, èi smezadali správne indexy a èi sa náhodou nesnaíme pristu-

pova „mimo“ po¾a.) Mimochodom, uvedené nepravidel-né pole zvládneme vytvori aj jediným riadkom:

int[][] aai = { { 1, 2 }, { 3, 4, 5 } };

Ktorý spôsob si vyberieme, závisí od toho, èi poznámeinicializaèné hodnoty vopred, alebo nie.

Dosia¾ sme ukázali len spôsoby, pomocou ktorých smenajvyššiu úroveò po¾a aai inicializovali zoznamom hod-

nôt. Pochopite¾ne, podobné výsledky môeme dosiahnupouitím operátora new:

int[][] aai = new int[2][2];

Takto deklarovaná a inicializovaná premenná aai ukazujena pole dvoch polí, obsahujúcich implicitné hodnoty, tedanuly. Inicializáciu môeme trochu obmedzi a zapísa:

int[][] aai = new int[2][];

Teraz premenná aai ukazuje na pole, obsahujúce dvepremenné typu int[], ale zatia¾ neinicializované, a tedaobsahujúce hodnoty null. Explicitne ich inicializujemenapríklad takto:

aai[0] = new int[2];

aai[1] = new int[3];

 Jednotlivé prvky polí druhej úrovne budú v takomto prí-pade obsahova, samozrejme, nuly.

Celá teória okolo viacrozmerných polí bude zrejme naprvý poh¾ad vyzera zloito a zamotane, hlavne pre zaèia-toèníka, ale len málo vecí je takých, aké sa nám zdajú naprvý poh¾ad. Staèí sa dobre zamyslie, vzia si ceruzku apapier a pokúsi sa celú situáciu nakresli. A takisto sitreba sadnú k poèítaèu, napísa zopár deklarácií a snaisa zisova, ktorá premenná má akú hodnotu, èo je defi-nované a èo pri pokuse o výpis vyhodí výnimku.

Zhròme všetky doteraz uvedené poznatky do nieko¾-kých bodov: ak v deklarácii uvedieme zoznam inicializaèných hod-

nôt, neuvádzame pre danú úroveò poèet prvkov po¾a; hociktorý inicializaèný zoznam na niektorej vnorenejúrovni môeme nahradi hodnotou null, potom budetáto èas po¾a neinicializovaná a príslušné podpoliabudeme musie vytvori explicitne; ak pouijeme na vytvorenie po¾a na ¾ubovo¾nej úrovnik¾úèové slovo new bez uvedenia inicializaèného zozna-mu, musíme uvies poèet prvkov tohto po¾a; pri vytváraní po¾a pomocou new môeme spravavynecha ¾ubovo¾ný poèet rozmerov polí niších úrovní– tieto polia potom budeme musie vytvori explicitne.

Na dokonalé ozrejmenie týchto pravidiel je tu ešte nazáver príklad po¾a s tromi rozmermi. Pouijeme štyri roz-lièné spôsoby vytvorenia po¾a s pouitím k¾úèového slovanew. Prvý spôsob vytvorí naraz celé pole 3 × 2 × 4 prvkov:

int[][][] aaai = new int[3][2][4];

 Jednotlivé prvky budú ma nulové hodnoty.Druhý spôsob vytvorí naraz prvú a druhú úroveò, tre-

tiu úroveò vytvoríme explicitne a „zubato“:

int[][][] aaai = new int[3][2][];aaai[0][0] = new int[2];aaai[0][1] = new int[5];aaai[1][0] = new int[4];aaai[1][1] = new int[3];aaai[2][0] = new int[6];aaai[2][1] = new int[2];

Polí tretej úrovne je, ako vidíme z príkladu, spolu šes (3× 2) a kadé bude ma inú dåku.

V treom spôsobe vytvoríme pomocou new len najvy-ššiu úroveò po¾a, druhú a tretiu úroveò vytvoríme expli-citne (ale naraz!)

int[][][] aaai = new int[3][][];aaai[0] = new int[2][4];aaai[1] = new int[3][3];

aaai[2] = new int[4][2];

Ako vidie z príkladu, prvé dvojrozmerné podpole budema 2 × 4 prvky, druhé 3 × 3 prvky a tretie 4 × 2 prvky.Všetky prvky budú inicializované nulovými hodnotami.

Modifikáciou tretieho spôsobu môeme vytvori ešteštvrtý spôsob, v ktorom by sa druhá a tretia úroveò vy-tvárali oddelene:

int[][][] aaai = new int[3][][];aaai[0] = new int[2][];aaai[0][0] = new int[2];aaai[0][1] = new int[5];aaai[1] = new int[3][];aaai[1][0] = new int[4];aaai[1][1] = new int[3];aaai[1][2] = new int[2];aaai[2] = new int[4][];aaai[2][0] = new int[6];aaai[2][1] = new int[2];aaai[2][2] = new int[5];aaai[2][3] = new int[3];

 Je oèividné, e ide v podstate o skombinovanie druhéhoa tretieho spôsobu. Výsledné pole bude ma (2 + 5) + (4+ 3 + 2) + (6 + 2 + 5 + 3), èo je spolu 32 prvkov.

Špecifiká polí v JaveNasledujúci odsek je urèený predovšetkým tým èitate-¾om, ktorí ovládajú jazyk C a nedajboe trpia utkveloupredstavou, e Java je také zjednodušené céèko. Tak pre-dovšetkým v céèku neexistuje samostatný typ pre reazecznakov. Na prácu so znakovými reazcami sa pouívapole znakov, teda typ char[] a v podstate vzh¾adom naznámu schizofréniu polí v céèku aj typ char*. V Jave niètakéto neplatí. Hoci je moné vytvori pole premennýchtypu char, bude nám poväèšine naniè, pretoe na prácus reazcami slúi vstavaný objektový typ String, resp.StringBuffer . Ich súèasou je mnostvo metód, ktoré naprácu s reazcami treba, take nemá prakticky nijakývýznam snai sa tvrdošijne operova so znakovými

po¾ami. A nehovoriac o tom, e v Jave nie sú reazce uko-nèené nulovým znakom.Druhá skutoènos je pre ortodoxných céèkarov ove¾a

priaznivejšia. Pri deklarácii po¾a toti netreba uvádzahranaté zátvorky len za názov typu, môeme ich podob-ne ako v C/C++ doplni za názov deklarovanej premen-nej, dokonca je dovolené oba spôsoby kombinova. Pre-mennú typu „pole polí celých èísel“ teda môeme dekla-rova a tromi rôznymi spôsobmi:

int[][] aai;int[] aai[];int aai[][];

Všetky tri spôsoby sú rovnocenné.

A zopár príkladovSkôr ne tému polí uzavrieme, ukáeme si ešte dva prí-klady. V prvom z nich vytvoríme zvláštnu konštrukciutrojuholníkovej „matice“ – dvojrozmerné pole, ktoréhopoèet ståpcov bude postupne rás v závislosti od porado-vého èísla riadka matice:

int[][] mat = new int[10][];for (int i = 0; i < mat.length; i++)

mat[i] = new int[i+1];

for (int i = 0; i < mat.length; i++)for (int j = 0; j < mat[i].length; j++)

mat[i][j] = (int)(Math.random() * 10);

for (int i = 0; i < mat.length; i++){

for (int j = 0; j < mat[i].length; j++)

System.out.print(mat[i][j] + " ");System.out.println("");}

Ponajprv maticu vytvoríme. V cykle for , kde sa dynamic-ky vytvárajú riadky matice, vidie, e poèet prvkov i-tehoriadka má by i + 1. Skutoène teda vytvoríme konštruk-

PC REVUE 15

JAVA POD LUPOU

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 16/36

ciu v tvare trojuholníka. V nasledujúcej dvojici cyklov formaticu naplníme náhodnými hodnotami a nakoniec tietohodnoty vypíšeme na obrazovku. Za pozornos stojí, evšetky cykly, ktoré s premennou mat pracujú, si zistiadåku príslušných polí pomocou výrazu mat.length, resp.mat[i].length. Netreba dáva pozor, èi cykly pracujú nadcelým po¾om, netreba zavádza iadne konštanty, jedno-ducho, programátorské selanky :-).

V druhom príklade predvedieme násobenie dvoch

matíc A a B, výsledok uloíme do matice C. Z algebryvieme, e násobi mono iba také dve matice, z ktorýchprvá má rovnaký poèet ståpcov ako druhá riadkov a výsle-dok „zdedí“ poèet riadkov prvej matice a poèet ståpcovdruhej matice:

int[][] A = new int[3][4];int[][] B = new int[4][2];int[][] C = new int[3][2];

for (int i = 0; i < A.length; i++)for (int j = 0; j < A[i].length; j++) A[i][j] = (int)(Math.random() * 10);

for (int i = 0; i < B.length; i++)for (int j = 0; j < B[i].length; j++)

B[i][j] = (int)(Math.random() * 10);

for (int i = 0; i < C.length; i++)for (int j = 0; j < C[i].length; j++)

for (int k = 0; k < A[i].length; k++)C[i][j] += A[i][k] * B[k][j];

System.out.println("A:");for (int i = 0; i < A.length; i++){

for (int j = 0; j < A[i].length; j++)System.out.print(A[i][j] + " ");

System.out.println("");}

System.out.println("\nB:");for (int i = 0; i < B.length; i++){

for (int j = 0; j < B[i].length; j++)System.out.print(B[i][j] + " ");

System.out.println("");

}

System.out.println("\nA.B:");for (int i = 0; i < C.length; i++){

for (int j = 0; j < C[i].length; j++)System.out.print(C[i][j] + " ");

System.out.println("");}

Prvé dva cykly for naplnia matice A a B náhodnými èísla-mi od 0 po 9. V treom cykle poèítame súèin oboch matíca výsledok ukladáme do prvkov matice C. S výhodouvyuijeme fakt, e jednotlivé prvky sú inicializovanénulami. Keby to tak nebolo, treba na vhodné miesto dopl-ni riadok C[i][j] = 0. Kam, to u ponechávam naèitate¾ovi. Zvyšok programu sa postará u len o výpisvšetkých troch matíc.

atva sa skonèila…… a my necháme polia po¾ami. V budúcej èasti prejdemek triedam a práci s objektmi, dovtedy dovidenia.

8.èas : Objekty a t r iedy

Na popud istého èitate¾a bude poènúc týmto èíslomPC REVUE moné nájs na webových stránkach PC REVUEv sekcii Programujeme kompletné zdrojové texty prebe-raných príkladov vo forme, na akú v èasopise (ia¾) nie jemiesto, a pod¾a situácie aj nieko¾ko príkladov navyše.To¾ko úvodná informácia, môeme sa vráti k Jave. Vôsmom pokraèovaní budeme hovori o deklarácii tried.

 Java je výrazne objektovo orientovaný jazyk. Javovskýprogram je tvorený mnoinou objektov, ktoré medzisebou komunikujú. Komunikácia sa deje prostredníctvomzasielania správ, ktoré sa v Jave realizuje ako klasické

volanie procedurálnych jednotiek, tzv. metód jednotli-vých objektov. Kadý objekt je tak charakterizovaný jed-nak mnoinou svojich èlenov, ktoré opisujú jehookamitý stav, a jednak mnoinou svojich metód, ktoréopisujú moné správanie objektu. Na zoznam metódmono pohliada ako na exportovaný zoznam správ, naktoré je objekt schopný reagova.

(Ešte poznámka k termínu èlen: Pouil som takúto for-muláciu, pretoe preklad pôvodného anglického slova

field, teda pole, by mohol kolidova s po¾om ako údajo-vým typom, ktoré sa pre zmenu v angliètine povie array.)

V Jave v zásade nie je moné vytvára objekty ad hoc,èírym vymenovaním ich obsahu (existujú anonymné trie-dy, ale tie nie je moné pouíva na najvyššej úrovni). Prvne môeme zaèa pouíva nejaký objekt, treba opísaschému, na základe ktorej sa tento objekt vygeneruje.Takejto schéme sa hovorí deklarácia triedy objektu. Vpôvodnom chápaní OO prístupu je trieda samostatnýmmetaobjektom, ktorý dokáe generova nové objekty.Èiastoène je to tak aj v Jave – poèas behu programu exis-tuje run-time reprezentácia kadej triedy, na základe kto-rej bol vytvorený nejaký objekt –, ale koncept triedy jeorientovaný viac syntakticky; trieda je teda syntaktickákonštrukcia, ktorá opisuje polia a metódy objektov.

Výhoda existencie tried je zrejmá: na základe jednej šab-lóny mono jednoducho vytvára objekty s rovnakouštruktúrou.

Ako teda vlastne vyzerá zdrojový kód javovskéhoprogramu? Je zvykom zapisova deklaráciu kadej triedydo samostatného súboru s príponou .java. Pri verejných(public) triedach je to dokonca nutnos a názov kadéhotakéhoto súboru sa musí zhodova s názvom verejnejtriedy v òom deklarovanej. Pri preklade programu sasúbory .java transformujú na súbory s príponou .class,ktoré obsahujú binárnu reprezentáciu jednotlivých tried.Ešte treba vyrieši otázku, ako má program zaèa. Akosme u spomínali, jedna z tried musí obsahova statickúmetódu main(), ktorú mono vyvola bez toho, aby exis-toval konkrétny objekt príslušnej triedy. Táto metóda sapotom musí postara o vytvorenie zodpovedajúcichobjektov (ak je to naším cie¾om).

Triedy a ich deklaráciaDeklaráciou triedy zavádzame do programu nový refere-nèný typ; samotná deklarácia opisuje jeho implementá-ciu. Triedy mono deklarova na rôznych úrovniach,pod¾a toho ich delíme na triedy na najvyššej úrovni (top-level) a na triedy vnorené (nested). Na zaèiatku sa bude-me zaobera výhradne triedami top-level, vnorené triedy(vnútorné, lokálne èi anonymné) prídu na rad a neskôr.

Pre názornos uvedieme hneï na zaèiatku kompletnúdeklaráciu jednoduchej triedy, na ktorú budeme v ïalšomvýklade odkazova. Triedu nazveme Point, bude totipredstavova bod v dvojrozmernom priestore. Taký bod je úplne opísaný svojimi dvoma súradnicami, ktoré budúpredstavova stav objektu. Náš bod bude schopný presu-nú sa na urèené súradnice a ïalej sa dokáe urèitýmobmedzeným spôsobom „zobrazi“.

Tu je zdrojový kód triedy Point, umiestnený v súborePoint.java:

public class Point{

private int x; // x−ová súradnicaprivate int y; // y−ová súradnica

 // konštruktory Point(){ this(0, 0);

}

Point(int x, int y){ this.x = x; this.y = y;

}

 // move() – presun na nové súradnice

public void move(int x, int y){ this.x = x; this.y = y;

}

 // getX() – vrátenie x−ovej súradnicepublic int getX(){

return x;}

 // getY() – vrátenie y−ovej súradnicepublic int getY(){

return y;}

 // show() – „zobrazenie“ bodupublic void show(){

System.out.println("Point at [" + x + ", " + y + "]");}

}

Všeobecný zápis deklarácie triedy vyzerá s urèitýmizjednodušeniami takto:

modifikátory class MenoTriedy

{

telo

}

Pre meno triedy platia rovnaké pravidlá ako pre identifi-kátor. Je zvykom zaèína meno triedy (a pokia¾ je totomeno viacslovným spojením, aj jednotlivé zloky mena)ve¾kým písmenom, ako napr. LineBuffer , TextFrame a i.

Pred k¾úèovým slovom class sa v deklarácii vyskytujútzv. modifikátory triedy, ktoré urèitým spôsobom upra-vujú vlastnosti novo deklarovanej triedy. Ako modifiká-tory triedy mono poui k¾úèové slová public, protec-ted, private, abstract, static èi final. Tri z týchto modifi-kátorov, menovite protected, private a static, monopoui len pre triedy deklarované v rámci inej triedy.

Modifikátory abstract a final dostanú zmysel v okamihu,keï budeme hovori o vzahu dediènosti medzi triedami,a koneène modifikátor public robí triedu verejnou, èovšak blišie vysvetlíme a pri rozprávaní o balíkoch.

Telo deklarácie triedy tvoria deklarácie èlenov triedy a jej metód. Okrem nich mono v triede nájs ešte deklará-cie vnorených tried a rozhraní, ale tie zatia¾ preskoèíme.

Deklarácia èlenov triedyPrvou èasou deklarácie triedy je deklarácia jej èlenov,v ktorých bude uloený stav objektu. Deklarácia èlenovtriedy sa nijako výrazne nelíši od deklarácie lokálnych pre-menných, samozrejme, ak neberieme do úvahy fakt, eèlenské premenné takto deklarované sú trvalou súèasoupríslušného objektu, zatia¾ èo lokálne premenné zanikajúpo opustení tela príslušného bloku kódu.

Všeobecný zápis deklarácie èlenov triedy vyzerá tedatakto:

modifikátory typ zoznam-deklarátorov ;

kde zoznam deklarátorov je èiarkami oddelená postup-nos deklarátorov v tvare

identifikátor 

alebo

identifikátor = inicializátor 

Ak sa pozrieme do triedy Point, nájdeme tam deklaráciudvoch èlenov, x a y, ktoré obsahujú x-ovú a y-ovú súradni-

cu príslušného bodu. Deklarácia èlena x vyzerá takto:private int x;

V tejto deklarácii sa nachádza jediný deklarátor, identifi-kátor x. Typom èlena x bude int. Okrem toho je súèasoudeklarácie jeden modifikátor, k¾úèové slovo private, ktoré

16 PC REVUE

JAVA POD LUPOU

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 17/36

hovorí o tom, e èlen x bude súkromným èlenom triedyPoint a nikto iný k nemu nebude ma prístup. Deklaráciaèlena y vyzerá podobne.

Obe deklarácie by sme mohli spoji do jednej:

private int x, y;

V takejto deklarácii je zoznam deklarátorov tvorenýdvoma identifikátormi, x a y. Dôleité je zapamäta si, emodifikátory a typ sa vzahujú na všetky identifikátoryv zozname deklarátorov.

Ak by sme pociovali potrebu oba èleny inicializovanejakou hodnotou, staèí deklarácie upravi na tvar:

private int x = 0;private int y = 0;

resp.

private int x = 0, y = 0;

Inicializovanie premenných (hocijakých) nulovou hodno-tou je však zbytoèné, to sa robí automaticky a okremtoho je trieda Point napísaná tak, e pokia¾ pri vytváranínovej inštancie (inštancia triedy = objekt vytvorený nazáklade tejto triedy) neuvedieme poèiatoèné hodnoty sú-

radníc, implicitne sa budú uvaova nulové.V deklarácii jednej triedy sa nesmú vyskytova dva

èleny s rovnakým názvom. Je to logické, pretoe by priprístupe k nim dochádzalo k nejednoznaènosti. Je všakmoné, i keï neve¾mi iaduce, pomenova èlen triedy rov-nako ako niektorú z metód triedy.

Keïe jediné, èo odlišuje deklaráciu èlenských pre-menných od deklarácie lokálnych premenných, sú modi-fikátory, zameriame sa teraz na ne. Ako modifikátory èle-nov triedy mono poui k¾úèové slová public, protected,private, static, final, transient a volatile.

Prvé tri modifikátory ovplyvòujú spôsob prístupu kèlenom. K¾úèovým slovom public sa oznaèujú èleny verej-né. K takýmto èlenom môe pristupova ktoko¾vek: sa-motné metódy objektu, metódy prípadných odvodených

objektov, ale aj metódy ¾ubovo¾ného iného objektu. Ve-rejné èleny treba pouíva opatrne, pretoe v zásade nie je moné zabráni nekonzistentnej manipulácii s nimibez toho, aby o tom samotný objekt nieèo vedel. K¾úèovéslovo private znamená presný opak: takto oznaèenéèleny sa povaujú za súkromné pre daný objekt. Okremmetód objektu k nim nemá prístup nikto, ani metódyodvodených tried. Takéto èleny sú úplne konformnés jedným zo základných pilierov OOP, konceptom zapuz-drenia. Jediná monos, ako meni hodnotu súkromnýchèlenov, je prostredníctvom metód objektu, a tie sú, samo-zrejme, úplne pod kontrolou objektu. Koneène poslednýmodifikátor protected definuje èleny ako tzv. chránené;takéto èleny sú prístupné na rozdiel od súkromných èle-nov aj odvodeným triedam, nie však metódam ostatnýchobjektov.

 Je chybou, ak pri deklarácii èlena triedy uvedieme viacako jeden z modifikátorov public, protected alebo priva-te. Je však moné neuvies ani jeden z týchto modifikáto-rov, v takom prípade sa èleny správajú ako chránené,s tým rozdielom, e k nim majú prístup metódy všetkýchtried nachádzajúcich sa v tom istom balíku. Viac na tútotému neskôr.

K¾úèové slovo static oznaèuje tzv. statické èleny. Roz-diel medzi nestatickými a statickými èlenmi je pomernezásadný. Zatia¾ èo nestatický èlen triedy existuje samo-statne v kadej kópii objektu, vytvoreného pod¾a tejtotriedy, statický èlen existuje pre kadú triedu práve je-den. Inak povedané, nestatické èleny sú súèasou kadej

vytvorenej inštancie triedy a zmena nestatického èlena jedného objektu nijako neovplyvòuje hodnotu rovnakopomenovaného èlena iného objektu tej istej triedy. Sta-tický èlen je, naopak, zdie¾aný všetkými objektmi jednejtriedy a de facto nie je súèasou jednotlivých objektov,ale samotnej triedy. Je teda moné s ním pracova ajvtedy, ak dosia¾ nebola vytvorená nijaká inštancia tejto

triedy. Pre nestatické èleny sa v angliètine pouíva aj ter-mín instance variables, statické sú potom class variables.Z oboch pomenovaní je okamite zrejmé, komu daný èlenpatrí.

Klasickým príkladom pouitia statického èlena bymohlo by poèítadlo vytvorených objektov. Kadé vytvo-renie novej inštancie by spôsobilo inkrementáciu poèí-tadla. Deklarácia èlena by mohla vyzera takto:

public static long counter = 0;

A v tele konštruktora triedy (èo to je, to sa dozviemeo chví¾u) by sa nachádzal riadok:

counter++;

Kompletný príklad takejto triedy nájdete na webovejstránke PC REVUE v sekcii Programujeme.

Ïalší modifikátor final hovorí o tom, e èlen taktooznaèený svoju hodnotu nebude meni a bude sa správaako pomenovaná konštanta. Je pochopite¾né, e finalèleny treba inicializova priamo v deklarácii. Èasto jevýhodné deklarova finálne èleny súèasne ako statické,potom máme monos pristupova k nim bez nutnosti

vytvára nový objekt. Ako príklad mono uvies takútodeklaráciu:

public class Const{

public static final double PI = 3.1415926;}

Trieda Const obsahuje jediný èlen PI, ktorý je statickýa zároveò konštantný. V programe by sme ho mohli sprí-stupni jednoduchým zápisom Const.PI a pouíva na-miesto literálu 3.1415926.

Modifikátor transient oznaèuje èleny, ktoré nie súsúèasou perzistentného stavu objektu. Inak povedané,keby sme chceli objekt serializova a uloi na perzis-tentné médium (napríklad do súboru na disku), alebo

hoci posla po sieti v rámci distribuovanej aplikácie, tran-zientné èleny by sa v takomto prípade neukladali – stavobjektu by bolo moné rekonštruova aj bez hodnôt tých-to èlenov.

Posledný èlenský modifikátor volatile sa pouíva naoznaèenie èlenov, ktorých hodnotu treba pri pouitíèlena vdy nanovo èíta z príslušnej oblasti pamäte. Primultithreadových aplikáciách je bené, e si jednotlivéthready uchovávajú lokálne kópie urèitých premenných,ktoré sa s hlavnou kópiou synchronizujú len v urèitýchokamihoch. Modifikátor volatile túto synchronizáciuvynucuje pri kadom pouití príslušnej premennej.

Deklarácia metód triedyMetódy na rozdiel od èlenov opisujú správanie objektov,

a preto budú obsahova kód. Deklarácia metódy vyzerávo všeobecnosti takto:

modifikátory výsledok názovMetódy ( parametre )

{

telo

}

Kadá metóda má svoj názov, pre ktorý platia známe pra-vidlá. Podobne ako pri pomenovávaní tried je zvykomzaèína jednotlivé slová vo viacslovnom pomenovaníve¾kým písmenom, názvy metód sa však obyèajne zaèí-najú malým písmenom, ako napr. moveTo, convertTo-Binary a pod.

Metóda sa z h¾adiska vykonávania programu správa

rovnakým spôsobom ako klasická céèkovská funkcia.Mono jej posla parametre a môe volajúcemu objektuvráti nejakú hodnotu. Typ výsledku sa v deklarácii zapi-suje pred názov metódy. Zoznam formálnych parametrovmetódy uvedieme do okrúhlych zátvoriek za názovmetódy. Jednotlivé parametre majú tvar klasickej dekla-raènej dvojice typ – názov a sú oddelené èiarkou. Názvy

 jednotlivých parametrov mono pouíva v tele metódyako lokálne premenné, ktoré sa naplnia príslušnými hod-notami pri volaní metódy.

Zoberme si ako príklad metódu move() triedy Point.Tu je pre úplnos jej deklarácia:

public void move(int x, int y){ this.x = x; this.y = y;

}

Vidíme, e táto metóda prijíma dva parametre, ktoré smepomenovali x a y a oba sú typu int. Zhodou okolností saaj oba èleny triedy Point volajú x a y, ale akýko¾vek samo-statný výskyt identifikátorov x a y v metóde move() tietodva èleny zakryje. Preto sme v tele metódy museli pouizápis   this.x = x. Jednoduché, nekvalifikované meno xnapravo od operátora priradenia predstavuje formálnyparameter metódy. Na¾avo od operátora priradenia sanachádza výraz this.x, ktorý sprístupòuje zakrytý èlen xtriedy Point. K¾úèové slovo this pouité vnútri metódypredstavuje referenciu na objekt, nad ktorým bola metó-da vyvolaná. Viac si povieme v odseku venovanom prí-stupu k èlenom triedy.

Metóda move() nevracia nijakú hodnotu. To je vyjad-rené k¾úèovým slovom void, pouitým ako typ návratovejhodnoty v deklarácii. Na rozdiel od C++ je toto jedinásituácia, v ktorej je moné k¾úèové slovo void poui.

Pozrime sa teraz na deklaráciu inej metódy, napr.getX(). Vidíme, e tá je deklarovaná s návratovým typomint. V tele metódy musíme preto zabezpeèi, aby sa neja-ká hodnota typu int vrátila volajúcemu objektu. Ako vy-plýva z názvu metódy, chceme zrejme vráti x-ovú súrad-nicu príslušného bodu, ktorá je uloená v èlene x. Naurèenie návratovej hodnoty pouijeme príkaz return x.Tento príkaz v ¾ubovo¾nej metóde spôsobí jej okamitéukonèenie a vrátenie príslušnej hodnoty. Je chyboupoui príkaz return bez argumentu v metóde, ktorá boladeklarovaná s návratovým typom iným ako void, rovna-ko je chybou poui return s argumentom v metóde de-klarovanej ako void.

Formálne parametre metódy môu by deklarovanés modifikátorom final, v takom prípade sa v tele metódypovaujú za konštantné a nemono ich meni.

Podobne ako pri deklarácii èlenov môu by súèasoudeklarácie metód triedy modifikátory. Pri metódachmono poui modifikátory public, protected, private,abstract, static, final, synchronized a native. Prvé trimajú rovnakú funkciu ako pri èlenoch, teda definujú úro-veò prístupu k metódam. Modifikátory abstract a finalsúvisia s mechanizmom dediènosti, take si o nich povie-me a nabudúce.

Popri statických èlenoch tried mono pomocou modi-

fikátora static ako statické definova aj metódy. Takétometódy sa dajú zavola aj v prípade, e nemáme k dispo-zícii nijaký objekt príslušnej triedy. V analógii s posiela-ním správ si mono predstavi, e príslušnú správu nepo-sielame konkrétnej inštancii triedy, ale samotnému me-taobjektu triedy. Pre statické metódy sa vilo aj pomeno-vanie class methods na rozdiel od bených instance met-hods. Príklad statickej metódy mono opä nájs nawebovej stránke PC REVUE.

Metódy oznaèené ako synchronized slúia na zabez-peèenie vzájomného vyluèovania pri prístupe k objektu(v podstate realizujú údajovú metaštruktúru monitor).Monostiam synchronizácie v Jave bude venovaná samo-statná èas.

Koneène metódy deklarované s modifikátorom native

sú implementované pomocou platformovo závisléhokódu. Takéto metódy neobsahujú telo, namiesto neho jedeklarácia ukonèená bodkoèiarkou, ako napr.:

public native void fileOpen(String name);

PC REVUE 17

JAVA POD LUPOU

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 18/36

Deklarácia konštruktorovŠpeciálnou mnoinou metód sú tzv. konštruktory. Dek-laráciu konštruktora spoznáme ¾ahko: neobsahuje špeci-fikáciu návratového typu a jeho názov sa presne zhodujes názvom triedy. Ako napovedá jeho názov, konštruktor je zodpovedný doslova za „skonštruovanie“ objektu pri jeho vytváraní. Konštruktorov môe by viac, musia savšak líši poètom a/alebo typmi argumentov. Konštruk-tory okrem jednej výnimky nikdy nevoláme klasickým

volaním metódy, vyvolávajú sa automaticky pri vznikunovej inštancie objektu.

Od bených metód sa konštruktory líšia predovšetkýmtým, e môeme k ich deklarácii pripoji len modifikáto-ry prístupu public, protected èi private. Menovite konš-truktory nemôu by abstraktné ani finálne a u vôbecnie statické.

V triede Point sa nachádzajú dva konštruktory. Jedenakceptuje dva argumenty typu int, ktoré beným spôso-bom skopíruje do èlenov x a y, druhý je bez argumentov.Všimnime si telo tohto konštruktora:

Point(){ this(0, 0);

}

Prvým (a v tomto prípade jediným) príkazom v tele konš-truktora je this(0, 0), ktorý spôsobí explicitné zavolanieiného konštruktora, ktorý dokáe akceptova dve celéèísla ako argumenty. Takýto konštruktor „zhodou okol-ností“ v triede Point máme, take vytvorenie inštancietriedy Point bez argumentov vytvorí v skutoènosti bods nulovými súradnicami. Tento prístup je pomerne bený– najkomplikovanejší konštruktor sa implementuje celý,zjednodušené verzie konštruktora potom volajú hlavnýkonštruktor s urèitými implicitnými hodnotami. Výhoda je zrejmá: pri zmene spôsobu konštrukcie objektu staèíprepísa kód jediného konštruktora.

V prípade, e trieda neobsahuje nijaký konštruktor,vytvorí prekladaè tzv. implicitný konštruktor bez argu-

mentov, ktorého jedinou úlohou bude zavola konštruk-tor nadradenej triedy (ale o tom a nabudúce).

Práca s objektmiSkôr ne s objektmi zaèneme pracova, musíme ich neja-kým spôsobom vytvori. To sa deje v dvoch krokoch.Predovšetkým treba deklarova premennú príslušnéhoreferenèného typu, v našom prípade teda napríklad:

Point p;

Podobne, ako to bolo pri poliach, ani teraz premenná pneobsahuje samotný objekt, dokonca dosia¾ iadna inš-tancia triedy Point vytvorená nebola (p obsahuje hodno-tu null).

Explicitné vytvorenie objektu typu Point a priradenieodkazu na tento objekt do premennej p zabezpeèímepomocou nasledujúceho príkazu:

p = new Point(10, −40);

Novú inštanciu teda vytvoríme pomocou k¾úèového slovanew, za ktoré uvedieme názov príslušnej triedy a dozátvoriek argumenty pre príslušný konštruktor. Vy-tvorenie inštancie sa vykoná v nasledujúcich krokoch:1. alokuje sa miesto v pamäti2. inicializujú sa èleny objektu na implicitné (nulové)

hodnoty3. vyhodnotia sa argumenty konštruktora4. vyberie sa a vykoná sa vhodný konštruktor5. referencia na nový objekt sa vráti ako hodnota celého

výrazuV prípade, e by sme chceli vytvori bod s implicitný-mi súradnicami, pouijeme príkaz:

Point q = new Point();

Len èo je objekt vytvorený, mono s ním pracova. Èleny

aj metódy sprístupòujeme pomocou klasickej bodkovejnotácie:

objekt.èlenobjekt.metóda

Keby niektorý z èlenov triedy Point bol verejne prístup-ný, mohli by sme napísa nieèo ako:

p.x = 20; // chybap.y = 50; // chyba

ale vzh¾adom na to, e oba èleny sú privátne, uvedenýzápis povedie k chybe pri preklade. Môeme však objek-tu p posla správu move alebo show (obe sú verejné):

p.move(20, 50);p.show();

Pouitie thisNa záver si ešte objasníme význam k¾úèového slova this.V ¾ubovo¾nej nestatickej metóde predstavuje this fiktívnulokálnu premennú, ktorej obsahom je referencia na tenobjekt, nad ktorým práve vykonávaná metóda pracuje.Ak teda napríklad objektu, na ktorý odkazuje prv defino-vaná premenná p, pošleme správu move, zavolá sa jehometóda move()a v jej tele bude this obsahova referenciuna tento objekt (inými slovami, bude plati podmienka p

== this). Je nadovšetko zrejmé, e odkaz na volaný objekt nemá

zmysel v statických metódach, take v takýchto metó-dach povedie akéko¾vek pouitie k¾úèového slova thisk neodvratnej prekladovej chybe.

NabudúceV májovom èísle budeme v rozprávaní o triedach po-kraèova – na rad príde dediènos, prekrývanie metód,abstraktné triedy a kadeèo iné. Dovtedy dovidenia.

9.èas : Dediènos  Byl pozdní veèer, první máj… hm, ako ten èas letí. No, ale

naspä k Jave. V minulej èasti sme hovorili o deklaráciitried a vytváraní objektov. Tento mesiac sa budeme za-obera spájaním tried do hierarchie dediènosti a princí-pom fungovania polymorfizmu.

Vzah dediènostiPri objektovo-orientovanom návrhu analytik èasto pri-chádza k zisteniu, e objekt, ktorý práve navrhol, sa doznaènej miery podobá inému objektu, dokáe reagovana rovnaké správy (i keï nie nutne rovnakým spôsobom)a naviac pridáva svoju vlastnú funkènos. Bolo by pretodobré, keby sa nový objekt dal vytvori na základe pôvod-ného, s explicitným vymenovaním nových vlastností a stým, e všetky nezmenené vlastnosti nový objekt auto-maticky „zdedí“. Tento jav, nazývaný dediènos, patrí me-

dzi základné, hoci nie fundamentálne princípy OOP. Jetakisto moné sa stretnú s iným pomenovaním vzahudediènosti – môeme poveda, e odvodený objekt, tzv.potomok, je špeciálnym prípadom nadradeného objektu,predka a naopak, predok je všeobecnejší prípad potomka.Vzah medzi oboma objektmi potom nazývame vzahšpecializácie/generalizácie.

V Jave sa dediènos realizuje úpravou deklarácie tried.Ak chceme, aby nová trieda bola potomkom inej, existu- júcej triedy, vyjadríme to pomocou k¾úèového slova extends.Tu je príklad:

 // Point.javapublic class Point{

protected int x, y;

Point(){ this(0, 0); }

Point(int x, int y){ this.x = x; this.y = y; }

public void move(int x, int y){ this.x = x; this.y = y; }

public void show(){ System.out.println("Point at ["

+ x + ", " + y + "]"); }}

 // ColorPoint.javapublic class ColorPoint extends Point{

protected int c;

ColorPoint(){ this(0, 0, 0); }

ColorPoint(int x, int y, int c){ super(0, 0); this.c = c; }

public void show(){ System.out.println("ColorPoint at ["

+ x + ", " + y + "], color " + c); }}

(Z dôvodu úspory miesta je výpis mierne „zhustený“.Èitate¾ovi sa neodporúèa tento spôsob zápisu pouíva vosvojich programoch.)

Zdrojový text triedy Point  je prakticky rovnaký akominule. Nová trieda ColorPoint predstavuje špeciálny prí-pad všeobecného bodu: farebný bod, ktorý okrem svojich

dvoch súradníc obsahuje naviac tretiu zloku – farbu.Pozrime sa na deklaráciu triedy ColorPoint. Za názvomtriedy objavíme spomínané k¾úèové slovo extends, zaktorým nasleduje názov nadradenej triedy, èo je v našomprípade Point. Nadradená trieda môe by len jedna,pretoe Java na rozdiel od C++ nepodporuje viacnásob-nú dediènos. V tele triedy sa nachádza len deklaráciapolí a metód, ktoré sú „iné“ oproti nadradenej triede.V triede ColorPoint konkrétne pribudol jeden údajovýèlen c, ktorý obsahuje informáciu o farbe. Èleny x a y trie-dy Point sa do novej triedy preberajú automaticky (hovo-ríme, e sa dedia). Ïalej v triede ColorPoint nájdeme dvakonštruktory. Tie musíme doplni vdy, pretoe konš-truktor, ako špeciálny typ metódy, sa nikdy nededí.Koneène poslednou metódou, ktorej deklaráciu v triede

ColorPoint nájdeme, je metóda show(). Táto metóda bysa za normálnych okolností prebrala z triedy Point, alemy chceme, aby sa farebný bod „zobrazoval“ iným spô-sobom ako obyèajný bod. Preto sme telo metódy show()prepísali vlastnou verziou. Príklad vytvorenia a práces objektom ColorPoint mono nájs na web stránkePC REVUE v sekcii Programujeme.

ImplementáciaPrincíp dedenia èlenov a metód je implementaène ve¾mi jednoduchý. Objekt potomka v sebe obsahuje akobykópiu objektu predka, so všetkými jeho èlenskými pre-mennými. Inštancia našej triedy ColorPoint tak napríkladv sebe obsahuje kompletnú inštanciu triedy Point a na-viac jeden „vlastný“ údajový èlen c. Èleny a metódy ob- jektu môeme teda rozdeli na dve skupiny: vlastné(deklarované v danej triede) a zdedené (deklarované vtriede èi triedach nadradených).

Hierarchia dediènosti sa neobmedzuje na jednu úro-veò. Ak by sme potrebovali vytvori špeciálnu verziufarebného bodu, odvodili by sme novú triedu, ktorá bybola potomkom triedy ColorPoint. Takto môeme zostro- ji celý hierarchický strom tried. Koreòom tohto stromu je v Jave preddefinovaná trieda Object, ktorá je priamym,èi nepriamym predkom kadej existujúcej javovskej trie-dy. Ak pri deklarácii triedy neuvedieme jej predka, auto-maticky sa nová trieda stáva potomkom triedy Object.

Táto superrodièovská trieda obsahuje nieko¾ko uni-verzálnych metód, spoloèných všetkým triedam a okremtoho umoòuje neobyèajnú flexibilitu pri narábaní s inš-tanciami objektov. V Jave, podobne ako vo väèšine objekto-vých jazykov, platí dôleité pravidlo: všade tam, kde sa oèa-káva inštancia nejakej triedy, môeme vdy poui inštan-ciu triedy odvodenej. Nasledujúci kód je teda korektný:

Point[] pts = new Point[3];pts[0] = new Point(10, 40);

18 PC REVUE

JAVA POD LUPOU

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 19/36

pts[1] = new ColorPoint(30, 5, 12);pts[2] = new ColorPoint();

Hoci sú jednotlivé prvky po¾a pts typu Point, priraïujemeim tie odkazy na objekty typu ColorPoint. Prekladaè anirun-time chybu neohlási, pretoe ako sme hovorili vyššie,kadý objekt typu ColorPoint v sebe v skutoènosti obsa-huje skrytý objekt typu Point. Opaèný spôsob pouitiav zásade nie je moný a vedie k chybe pri preklade èi pri

behu programu. Ak potrebujeme takto uloi do po¾aalebo inej údajovej štruktúry nepríliš súvisiace objekty,vdy môeme poui ako spoloèný typ Object.

Finálne triedyV minulom pokraèovaní seriálu sme hovorili okrem inéhoo tom, e kadá trieda môe by deklarovaná s modifiká-torom final. Takáto trieda sa povauje za „finálnu“ – nie je toti od nej moné odvodi iadneho potomka. Pokuso deklaráciu triedy, ktorá by rozširovala finálnu triedu,skonèí chybou pri preklade.

Zmysel existencie finálnych tried vyplýva z práve spo-menutého pravidla „potomok môe vdy zastúpi pred-ka“. Ako finálnu obyèajne definujeme takú triedu, pri kto-rej sa potrebujeme spo¾ahnú na jej funkènos a chceme

zabráni monosti nahradi ju inou triedou (odvodenou).

Skrývanie èlenovOdvodená trieda môe obsahova údajový èlen s rovna-kým menom, ako má niektorý èlen v nadradenej triede,rovnakého alebo aj odlišného typu. V takejto situácii ho-voríme, e èlen potomka skrýva èlen predka. Termín skrý-vanie je na rozdiel od nasledujúceho prípadu presnýmprekladom pôvodného anglického výrazu „hiding“. Skry-tý èlen nie je prístupný beným spôsobom; ak s ním chce-me pracova, musíme ho explicitne sprístupni pomocouk¾úèového slova super. Zoberme si príklad:

class A { protected int x = 1; }

class B extends A 

{protected int x = 2;public void print(){

System.out.println("super.x = " + super.x);System.out.println("x = " + x);

}}

Ak vytvoríme objekt triedy B a zavoláme jeho metóduprint(), dostaneme takýto výstup:

super.x = 1x = 2

Názov x v metóde print() predstavuje celoèíselný èlentriedy B. K èlenu x zdedenému z triedy A sa dostaneme

pomocou výrazu super.x. Podobne ako this sprístupòujeaktuálnu inštanciu, k¾úèové slovo super predstavuje od-kaz na nadradenú inštanciu.

V prípade, e sa potrebujeme dosta k zakrytémuèlenu z niektorého nepriameho predka (t. j. viac ako o jednu úroveò smerom „nahor“), logické by bolo pouizápis super.super.x. To bohuia¾ nefunguje, je nutnéexplicitne pretypova this na príslušnú nadtriedu:

public class C extends B{

protected boolean x;public void anotherPrint(){ System.out.println(((A)this).x); }

}

K èlenu x z triedy A sa v metódach triedy C dostanemepomocou výrazu ((A)this).x. V prípade, e by zakrytý èlenbol statický, mono poui aj výraz A.x, resp. B.x.

Pozrime sa ešte, èo sa stane, ak pristupujeme k objek-tu potomka pomocou premennej typu predka:

B b = new B(); A a = b;

System.out.println("a.x = " + a.x);System.out.println("b.x = " + b.x);

Máme dve premenné a a b, jednu typu A, druhú typuB. Obe však odkazujú na tú istú inštanciu triedy B. Ho-reuvedený kód vypíše na obrazovku toto:

a.x = 1 b.x = 2

 Je zrejmé, e výraz a.x sprístupòuje skrytý èlen x, ktorýtrieda B zdedila od triedy A. Dôvod je jednoduchý – pre-menná a je typu A a v Jave pri prístupe k údajovým èle-nom triedy nezáleí na skutoènom type objektu, ale lenna type výrazu, pomocou ktorého sa na objekt odvoláva-me. Tento typ je známy u pri preklade. Ak by sme potre-bovali pracova s èlenom tej triedy, ktorej inštanciouobjekt skutoène je, bude nutné poui iný spôsob, akouvidíme z nasledujúceho odseku.

Skrývanie a predefinovanie metódV minulej èasti sme hovorili o tom, e dve metódy jednejtriedy môu ma rovnaký názov, ak sa líšia poètoma/alebo typmi svojich argumentov. Tomuto javu sa vangliètine hovorí „method overloading“. Vhodný preklad

termínu „overloading“ akosi neexistuje – èasto pouíva-ný kalk „preaovanie“ má od skutoèného významu po-merne ïaleko. Snáï by sa dal poui výraz prekrývaniemetód.

Iná situácia nastane v prípade, e deklarujeme v odvo-denej triede metódu s rovnakým názvom, ako má niekto-rá zdedená metóda. O takejto metóde hovoríme, e pre-definuje metódu nadradenej triedy. V angliètine sapouíva termín „method overriding“. Metóda v odvode-nej triede nesmie ma iný typ návratovej hodnoty akopredefinovaná metóda.

Predefinovanie metód pouívame vtedy, keï námreakcia nadradenej triedy na príslušnú správu nevyhovu- je a chceme, aby sa odvodená trieda správala ináè. V prí-pade triedy ColorPoint zo zaèiatku èlánku napríklad

chceme, aby sa farebný bod „zobrazoval“ iným spôsobomako obyèajný, bezfarebný bod. Z toho dôvodu v triedeColorPoint predefinujeme metódu show(). Naproti tomumetóda move() predefinovaná nie je; dedí sa bezo zmenyz triedy Point, pretoe jej telo nám vyhovuje – farebnýbod sa „pohybuje“ tak isto, ako obyèajný bod.

Pri predefinovaní metódy sa môe sta, e potrebuje-me predsa len zavola normálne neprístupnú metódunadradenej triedy. V takej situácii opä pomôe k¾úèovéslovo super, ako vidno aj z nasledujúceho príkladu:

class A {

public void foo(){ System.out.println("Calling A.foo()"); }

}

class B extends A {

public void foo(){ System.out.println("Calling B.foo()"); }

public void print(){

foo();super.foo();

}}

Ak nad objektom triedy B zavoláme metódu print(),dostaneme na obrazovke takýto výpis:

Calling B.foo()Calling A.foo()

Výraz super.foo() teda vyvolal predefinovanú metódufoo() triedy A.

V prípade, e v odvodenej triede deklarujeme statickúmetódu s rovnakou signatúrou ako niektorá metóda nad-radenej triedy, nehovoríme o predefinovaní, ale, podobneako pri údajových èlenoch, o skrytí metódy. Aj skrytú

metódu mono sprístupni prostredníctvom k¾úèovéhoslova super.

Nie je moné statickú metódu predefinova nestatic-kou a takisto nie je moné nestatickú metódu skry pro-stredníctvom statickej metódy, oboje vedie k chybe pripreklade.

Pri prístupe k metódam potomka prostredníctvompremennej typu predka dochádza oproti údajovým èle-nom k závanej odlišnosti. Viac ukáe príklad:

B b = new B(); A a = b; b.foo();a.foo();

Po prebehnutí tohto úseku programu by sme po pred-chádzajúcej skúsenosti oèakávali, e sa v prvom prípadezavolá metóda triedy B a v druhom prípade metóda trie-dy A. Dostaneme však nasledovný výstup:

Calling B.foo()Calling B.foo()

Èo sa stalo? V oboch prípadoch sa zavolala metódafoo() triedy B, hoci premenná a je typu A. V Jave sa toti(na rozdiel od prístupu k údajovým èlenom) pri volaní

metódy urèí skutoèný, run-time typ objektu, ktoréhometódu voláme a pod¾a tohto typu sa vyberie správnaverzia metódy z príslušnej triedy.

Ak porovnáme Javu s C++, zistíme, e zatia¾ èov C++ sú èlenské funkcie implicitne nevirtuálne, so sta-tickou väzbou (early binding – správna funkcia sa vyberáu poèas prekladu), v Jave sú naopak metódy automatic-ky „virtuálne“, dynamicky viazané (late binding – kon-krétna metóda sa vyberá a poèas behu programu, pod¾askutoèného typu objektu). Ak v C++ existuje monoszmeni funkciu z nevirtuálnej na virtuálnu, k¾úèovým slo-vom virtual, malo by v Jave by moné deklarova metó-du ako nevirtuálnu. To sa zabezpeèí k¾úèovým slovomfinal. Metóda deklarovaná ako finálna nemôe by v od-vodenej triede predefinovaná a pri jej volaní sa nevyhod-

nocuje dynamický typ objektu.Mimochodom, práve dynamickému vyhodnocovaniumetód vïaèíme za polymorfné správanie objektov v Jave.Polymorfizmus znamená v preklade mnohotvaros; rôz-nym polymorfným objektom môeme posla jednu a túistú správu a ony na òu zareagujú kadý „po svojom“.V Jave sa posielanie správ realizuje volaním metód.Programátorovi teda môe by úplne jedno, nad akýmobjektom metódu volá; jej správna verzia sa toti nájdepoèas behu programu na základe skutoèného typu objektu.

Konštruktory a dediènos Na zaèiatku èlánku sme spomínali, e konštruktory saautomaticky nededia. Pre kadú odvodenú triedu pretomusíme napísa konštruktor nanovo. Môe sa však sta,

e konštruktor odvodenej triedy u z princípu bude èias-toène opakova kód konštruktora nadradenej triedy.Zoberme si náš farebný bod. Ten zrejme budeme konš-

truova rovnako ako obyèajný bod, len naviac do jehostavu uloíme informáciu o farbe. Bolo by preto nanajvýšefektívne, keby sme mali monos poveda, e farebnýbod sa má skonštruova presne tak isto ako jeho predok,obyèajný bod, ale naviac si má ešte zapamäta svojufarbu. Našastie v Jave túto monos máme – ako prvýpríkaz konštruktora môeme uvies k¾úèové slovo supernasledované prípadnými argumentmi v okrúhlych zá-tvorkách. To spôsobí zavolanie príslušného konštruktoranadradenej triedy. (Ak iaden s vhodným poètom a typmiargumentov neexistuje, dôjde samozrejme pri prekladek chybe.) Volanie superkonštruktora nie je povinné, ale

ak ho neuvedieme, resp. ho neumiestnime ako prvý prí-kaz konštruktora, doplní sa namiesto neho automatickyvolanie bezargumentového konštruktora (t. j. super();).Problém by mohol nasta v prípade, e nadradená triedanemá konštruktor bez argumentov. Ak však k takejto si-tuácii dôjde, je „nieèo prehnité“ v návrhu tried.

PC REVUE 19

JAVA POD LUPOU

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 20/36

 Jedinou výnimkou, kedy nie je volanie nadradenéhokonštruktora nutné a ani sa automaticky nedopåòa, je prí-pad, keï z jedného konštruktora voláme iný v rámci tejistej triedy. O tom sme hovorili minule – ako jediný prí-kaz konštruktora v takomto prípade bude k¾úèové slovothis nasledované vhodnými argumentmi v okrúhlych zá-tvorkách.

Pouitie k¾úèového slova super pri volaní konštrukto-ra nadradenej triedy vidno v triede ColorPoint. Jej konš-

truktor s tromi argumentmi prvé dva (to sú súradnicebodu) pekne krásne pošle nadradenému konštruktorua ani v najmenšom sa nestará, èo sa s nimi bude dia.Zaujíma ho a tretí argument, ktorý si uloí „pre vlastnúpotrebu“. Ako vidno, pri takomto prístupe je konštruova-nie objektu rozdelené do jednotlivých hierarchických stu-pòov a kadá trieda, resp. jej konštruktor, inicializuje lento, èo sama do objektu pridala. No a ak by sa náhodoustalo, e by bolo nutné zmeni spôsob inicializácie inš-tancií triedy Point, trieda ColorPoint zostane bezo zmien.

Riadenie prístupuTeraz, keï u vieme, ako je to s odvodzovaním novýchtried pomocou dedenia, môeme doplni informáciez minulej èasti seriálu o modifikátoroch prístupu. Ako si

èitate¾ iste spomenie, deklaráciu kadého èlena alebometódy môeme doplni jedným z k¾úèových slov priva-te, protected alebo public. Pri nastavovaní prístupu nezá-leí na tom, èi sú deklarované èleny alebo metódy static-ké alebo nestatické.

Èleny a metódy deklarované ako private sú pre danútriedu privátne, súkromné. Prístup k nim majú len metó-dy tejto triedy a nikto iný. Nemono s nimi pracova„zvonka“ a nemajú k nim prístup ani triedy odvodené.Privátne èleny realizujú princíp zapuzdrenia, skrytiastavu objektu pred jeho okolím. Ešte na vyjasnenie: v ori-ginálnej špecifikácii Javy sa hovorí, e privátne èlenya metódy sa nededia. To je pravda, ale myslí sa tým, eich odvodené triedy „nevidia“ a nemôu k nim nijako pri-stupova. Napriek tomu sa však tieto èleny v inštanciách

odvodených tried fyzicky nachádzajú (inak by to aninešlo a celý mechanizmus dediènosti by bol naniè).

Èleny a metódy s modifikátorom protected („chráne-né“) sú takisto zvonka neprístupné, na rozdiel od privát-nych èlenov k nim však majú prístup aj metódy odvode-ných tried. Pokia¾ teda máme objektovú hierarchiunavrhnutú tak, e odvodené triedy musia pracova s èlen-mi nadradených tried, je nutné tieto èleny deklarova akochránené. Príkladom môu by triedy Point a ColorPointz úvodu èlánku. Údajové èleny x a  y sú v triede Pointdeklarované ako protected, vïaka èomu ich metódashow() triedy ColorPoint môe poui na výpis súradnícbodu. Treba si však uvedomi, e v zásade je takmer vdymoné ma všetky èleny privátne a sprístupòova ichpomocou metód, take vo¾ba medzi private a protected

prístupom je viac-menej otázkou poadovanej efektivityimplementácie.

Koneène modifikátor public deklaruje èleny a metódyako verejné, take k nim má prístup ktoko¾vek, odkia¾-ko¾vek. Z pochopite¾ných dôvodov nie je ve¾mi rozumnédeklarova v triede verejné údajové èleny – môe sa totista, e ich ktorýsi objekt modifikuje nesprávnym, nekon-zistentným spôsobom a u je narušená integrita progra-mu. Verejné èleny majú zmysel predovšetkým v triedach,ktoré slúia ako jednoduché štruktúrované typy (analó-gia struct v C++).

Aby sme boli presní, existuje ešte jedna úroveò prí-stupu – ak neuvedieme ani jeden zo spomenutých trochmodifikátorov, èlen alebo metóda má tzv. implicitnúalebo balíkovú úroveò prístupu. Ale o tom a nabudúce.

Od rozhraní k balíkomV ïalšom pokraèovaní prídu na rad abstraktné triedy,rozhrania a balíky. Dovidenia opä o mesiac.

10.èas : Abst raktné t r iedy,rozhrania, bal íky

Rozprávanie o triedach by nebolo úplné bez zmienkyo abstraktných triedach a abstraktných metódach. S abstrakt-nými triedami úzko súvisí zvláštny údajový typ – rozhra-nia.

Abstraktné triedyDo deklarácie ¾ubovo¾nej triedy môeme doplni modifi-kátor abstract. O takej triede potom hovoríme, e jeabstraktná, a chceme tým vyjadri, e je nejakým spôso-bom „nedokonèená“ alebo sa aspoò za nedokonèenú mápovaova. Z abstraktných tried nemono vytvára inš-tancie, mono však od nich odvodzova nové triedy,preto abstraktnú triedu ve¾mi pravdepodobne nájdemena niektorom medzistupni èi priamo na vrchole objekto-vej hierarchie. Takisto môeme deklarova premennú,ktorej typom bude abstraktná trieda, a uloi do nejodkaz na reálnu inštanciu niektorej z odvodených tried.

Ako príklad by sme mohli uvies hierarchiu grafickýchobjektov v kresliacom programe. Na vrchole objektovéhostromu sa zrejme bude nachádza nejaká univerzálnatrieda, nazvime ju napríklad GrObject, implementujúcaminimálnu mnoinu spoloèných vlastností kadého gra-fického objektu. V programe však sotva nastane situácia,keï by sme vytvorili reálnu inštanciu tejto triedy – prav-depodobne vytvoríme pole typu GrObject[], ktorého jed-notlivé prvky budú ukazova na inštancie  potomkov trie-dy GrObject. Univerzálna trieda je teda výborným kandi-dátom na „zabstraktnenie“.

Abstraktné metódyAbstraktná trieda môe by s výnimkou modifikátoraabstract v zásade totoná s neabstraktnou triedou,v takom prípade jediným rozdielom je nemonos vytvo-ri objekt tejto triedy. (Predpokladá sa, e od abstraktnej

triedy budeme odvodzova potomkov; ak chceme lenzabráni vytváraniu inštancií, je správnejšie deklarovakonštruktor triedy ako privátny – èleny triedy by všakpotom mali by výhradne statické.) Pokia¾ nepoviemeinak, je ¾ubovo¾ný potomok takejto triedy neabstraktný.

Abstraktná trieda však môe obsahova aj jednu aleboviac abstraktných metód. To sú metódy deklarovanés modifikátorom abstract. Deklarácia abstraktnýchmetód informuje o názve, poète a typoch argumentov a otype návratovej hodnoty, neobsahuje však telo metódy, t. j. jej implementáciu (deklaráciu treba ukonèi bodkoèiar-kou). Kadá trieda odvodená od takejto abstraktnej trie-dy potom musí implementova všetky zdedené abstrakt-né metódy, inak sa sama stáva abstraktnou. Odvodenátrieda môe zdedenú abstraktnú metódu okrem imple-

mentácie (t. j. predefinovania plnohodnotnou, neab-straktnou metódou) predefinova inou, vlastnou ab-straktnou metódou.

Ako abstraktné sa obyèajne deklarujú metódy, ktoré jenereálne alebo nemá zmysel naprogramova pre všeo-becný typ objektu. Príkladom v našej kolekcii grafickýchobjektov môe by metóda show(), ktorá prikazuje objek-tu, aby sa zobrazil. Zatia¾ èo o kadej konkrétnej triede -grafickom objekte, ako napr. bod, èiara, krunica – doká-eme poveda, ako sa má zobrazi, univerzálna supertrie-da GrObject bude ma metódu show() deklarovanú akoabstraktnú – sotva by sme vedeli urèi, ako sa má objektGrObject zobrazi.

Abstraktnou nemôe by hociktorá metóda. Prekladaèohlási chybu pri pokuse o abstraktnú deklaráciu metódy

s modifikátorom private, static alebo final. Privátnu me-tódu nie sme schopní implementova v odvodenej triede,pretoe sa nededí, finálna metóda má predefinovaniezakázané a pri statických metódach abstraktnos akosistráca zmysel. Ani trieda ako celok nemôe by deklaro-vaná ako abstraktná a finálna zároveò.

Abstraktné metódy nemajú telo. Je preto chybou sna-i sa o ich vyvolanie z inštancie odvodenej triedy pro-stredníctvom k¾úèového slova super.

Trieda, ktorá obsahuje abstraktné metódy, èi u vlast-né alebo zdedené, musí by deklarovaná s modifikátoromabstract, inak dôjde pri preklade k chybe.

Príklad abstraktnej triedyAko príklad si uvedieme ve¾mi zjednodušenú deklaráciu

spomínanej abstraktnej triedy GrObject, od ktorej odvo-díme u v predošlých èastiach pouitú triedu Point, ktorábude reprezentova bod, a ešte jednu triedu Circle, ktorábude implementova krunicu. S oh¾adom na obmedzenýrozsah èasopisu sú deklarácie èiastoène oklieštené – kom-pletnú verziu nájdete na webovej stránke PC REVUE:

public abstract class GrObject{

public abstract void show();}

public class Point extends GrObject{

private int x, y;

public void show(){ System.out.println("Point at ["+ x + ", " + y + "]"); }

}

public class Circle extends GrObject{

private int x, y, r;

public void show(){ System.out.println("Circle at ["

+ x + ", " + y + "]"); }}

(V triedach chýbajú predovšetkým konštruktory – ale tiesi šikovný èitate¾ dokáe doplni u aj sám.)

RozhraniaS abstraktnými metódami úzko súvisí koncept rozhraní. Rozhranie (interface) v jazyku Java predstavuje referenè-ný typ. Je blízkym príbuzným triedy, nie je však monévytvára jeho inštancie a jeho èlenmi môu by len sta-tické finálne údajové èleny a abstraktné metódy.Ktoráko¾vek trieda môe o sebe poveda, e dané rozhra-nie implementuje – tým sa zaväzuje, e implementujevšetky abstraktné metódy uvedené v rozhraní. Tentozáväzok nemusí nevyhnutne splni, ale potom sa stávaabstraktnou a musí by tak aj deklarovaná. Rozhranie sateda v podstate správa ako (špeciálna) abstraktná trieda.

Súèasou rozhrania môu by údajové èleny, ktoré saautomaticky povaujú za verejné, finálne a statické (jedovolené príslušné modifikátory vynecha). Takéto konš-

tantné èleny môe potom implementujúca triedapouíva ako svoje vlastné (t. j. ako keby ich zdedila).

Deklarácia rozhrania je znaène podobná deklaráciitriedy:

modifikátory interface MenoRozhrania    

extends Rozhranie, Rozhranie …{

telo}

Modifikátormi rozhrania môu by k¾úèové slová public,protected, private, abstract a static. Prvé z nich hovorío tom, e deklarované rozhranie je verejné a prístupnékomuko¾vek, odkia¾ko¾vek. Modifikátory protected, priva-

te a static sa pouívajú iba pri vnorených rozhraniach,ktoré zatia¾ preskoèíme. Posledný modifikátor abstract jeredundantný, pretoe kadé rozhranie je implicitneabstraktné. Povauje sa za zastaraný a neodporúèa sa hopouíva.

Rozhrania mono podobne ako triedy zoraïova do hie-rarchie dediènosti. Rozdiel oproti triedam je v tom, e roz-

20 PC REVUE

JAVA POD LUPOU

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 21/36

hranie môe by potomkom viacerých superrozhraní.Nadradené rozhrania sa uvádzajú v deklarácii rozhraniaspolu so známou klauzulou extends. Zoznam rozhraníodde¾ujeme èiarkou. Ak trieda implementuje rozhranie,ktoré je potomkom iných rozhraní, musí táto trieda imple-mentova okrem abstraktných metód samotného rozhra-nia všetky zdedené abstraktné metódy jeho predkov.

Telo rozhrania obsahuje deklaráciu jednotlivýchabstraktných metód a/alebo údajových èlenov. Všetky

èleny i metódy sú implicitne verejné. Inak pre ne platia vzásade rovnaké pravidlá ako pri triedach – nemonodeklarova dva èleny s rovnakým názvom, èlen potomkaskrýva rovnako pomenovaný èlen predka, abstraktnámetóda potomka predefinuje abstraktnú metódu predkas rovnakou signatúrou.

Údajové èleny musia v deklarácii obsahova inicializá-tory (konštanty, ktorých hodnotu nepoznáme, by nám,pochopite¾ne, boli na niè). Metódy môeme deklarovas modifikátormi public a abstract, ale je to zbytoènéa neodporúèa sa ich pouíva. Metódy rozhraní nesmúby statické, natívne ani synchronizované.

V súvislosti s viacnásobnou dediènosou môe dôjsk situácii, e rozhranie zdedí dva èleny s rovnakým náz-vom. Nie je to chyba; k tej dôjde a pri pokuse o prístupk tomuto èlenu pouitím nekvalifikovaného mena. Naviacnásobné èleny preto treba vdy odkazova pomocouúplného mena v tvare  Rozhranie.èlen. Ïalej sa môe sta,e rozhranie zdedí jeden a ten istý èlen viackrát (cezrôzne cesty v strome dediènosti). V takom prípade satento èlen bude v rozhraní nachádza iba raz (podobne,ako keby sme v C++ pouili k¾úèové slovo virtual).

Implementácia rozhraníTrieda, ktorá sa zaväzuje implementova niektoré roz-hranie, musí túto skutoènos explicitne oznámi vo svojejdeklarácii pomocou klauzuly implements, nasledovanejzoznamom implementovaných rozhraní. Táto klauzula sauvádza za klauzulu extends, urèujúcou predka triedy.Úplná schéma deklarácie triedy potom vyzerá takto:

modifikátory class MenoTriedy    

extends MenoPredka    

implements Rozhranie, Rozhranie …{

telo}

Ako vidie, trieda môe implementova aj viac ako jednorozhranie, vïaka èomu je moné do urèitej miery zabez-peèi viacnásobné dedenie, ktoré na rozdiel od C++v tradiènej forme v Jave nenájdeme. Autori Javy zastávajúnázor, e nutnos viacnásobnej dediènosti je známkounedokonalého návrhu objektovej hierarchie, ale našastiedoplnením rozhraní do návrhu jazyka umonili progra-

mátorom zariadi sa pod¾a svojich potrieb.Rozhrania, ktoré trieda implementuje, sú jej superroz-

hraniami (alebo by bolo lepšie nadradenými rozhrania-mi? …ach, tá slovenèina). Trieda môe ma aj nepriamesuperrozhrania – to sú jednak predkovia priamych super-rozhraní triedy, jednak superrozhrania niektoréhoz predkov triedy (a aj rôzne iné kombinácie predkova superrozhraní). Jednoduché, nie?

Trieda môe pri implementácii rozhraní jedinou dekla-ráciou metódy zabi dve a viac múch jednou ranou – tov prípade, keï jej superrozhrania obsahujú metódy s rov-nakou signatúrou. Tieto metódy sa však nesmú líšitypom návratovej hodnoty, inak nebude existova nijakýspôsob, ako implementova obe metódy a súèasnedodra pravidlo, e v jednej triede sa nesmú nachádza

dve metódy s rovnakou signatúrou.

Praktická ukákaAby sme neomie¾ali len suchú teóriu, ukáeme si dekla-ráciu a implementáciu rozhrania na príklade. Do našejkolekcie grafických objektov doplníme rozhranie

Resizable, ktoré bude od objektov poadova implemen-táciu metódy na zmenu ich ve¾kosti, a rozhranieColorable, v ktorom sa budú nachádza metódy nazmenu farby objektu. (Mimochodom, je zvykom rozhra-nia pomenováva tak, aby sa konèili príponou -able.)

public interface Resizable{ void resize(int factor);

}

public interface Colorable{

int RED = 1, GREEN = 2, BLUE = 4; void setColor(int color);int getColor();

}

Pre verejné rozhrania platí rovnaké pravidlo ako preverejné triedy – ich zdrojový text sa musí nachádzav súbore s rovnakým názvom a príponou .java. Naše dverozhrania teda treba uloi do súborov Resizable.javaa Colorable.java.

Rozhranie Resizable obsahuje jedinú metódu resize(),ktorá slúi na zmenu ve¾kosti objektu pod¾a hodnotyargumentu factor . Druhé rozhranie, Colorable, zahàòa

dve metódy na nastavenie farby (setColor()) a zistenie jejhodnoty (getColor()) a tri konštanty RED, GREEN a BLUE.Vytvoríme ïalej novú triedu ColorPoint, ktorá bude

potomkom triedy Point a navyše bude implementovarozhranie Colorable:

public class ColorPoint extends Pointimplements Colorable

{private int color;

public void setColor(int color){ this.color = color; }

public int getColor(){ return color; }

}

(V triede opätovne chýba konštruktor, kompletný zdrojo-vý text nájdete na webe.)

Trieda ColorPoint obsahuje implementáciu metódsetColor() a getColor(), take skutoène implementujerozhranie Colorable.

Ako príklad implementácie rozhrania Resizable upra-víme deklaráciu triedy Circle:

public class Circle extends GrObjectimplements Resizable

{private int x, y, r;

public void resize(int factor){ r *= factor; }

public void show(){ System.out.println("Circle at ["

+ x + ", " + y + "]"); }}

Zmenu ve¾kosti krunice dosiahneme jednoduchým vy-násobením jej polomeru parametrom factor .

Ako sme spomínali, rozhrania v Jave sú samostatnýmireferenènými typmi. Je teda moné deklarova premennútypu niektorého rozhrania. Takáto premenná potommôe (a vlastne musí) odkazova na inštanciu triedy,ktorá dané rozhranie implementuje. Nasledujúce dva prí-klady sú teda korektné:

Colorable c = new ColorPoint(1, 2);

c.setColor(RED);

Resizable r = new Circle(0, 0, 10);r.resize(3);r.show();

BalíkyAko sme nieko¾kokrát naznaèili v predchádzajúcich èas-tiach, triedy v Jave sú zoskupované do tzv. balíkov (pac-kages). Balík je mnoina tried, ktoré zvyèajne spolu neja-kým spôsobom súvisia. Okrem toho je vïaka balíkommoné deklarova dve a viac tried èi rozhraní s rovnakýmnázvom – pokia¾ sa budú nachádza v rôznych balíkoch.

Kadý balík má svoj názov, ktorý by mal pozostávavýhradne z malých písmen. Èlenmi balíka môu by trie-

dy, rozhrania a podriadené balíky, usporiadanie je tedahierarchické. Mono, samozrejme, vytvori balík, ktorýneobsahuje iadne triedy/rozhrania, ale èisto len podba-líky. Úplné (tzv. plne kvalifikované) meno balíka Q, ktorýpatrí do balíka P, vytvoríme klasickou bodkovou metódouako P.Q. Plne kvalifikované meno ¾ubovo¾nej triedy, ktorá je prvkom niektorého balíka, dostaneme bodkovým spo- jením úplného mena tohto balíka a mena triedy.

Zoberme si ako príklad triedy štandardného aplikaè-ného programového rozhrania Java API. Všetky nepriamopatria do hlavného balíka s názvom java (alebo v novšíchverziách Javy aj do balíka javax). Balík java neobsahujeiadne triedy, zato však v òom nájdeme mnoho podbalí-kov, ako napríklad awt, lang, net, util a pod. Kadý z tých-to podbalíkov je urèený pre iný okruh úloh:  java.awt

napríklad poskytuje triedy na realizáciu grafickéhopouívate¾ského rozhrania, triedy balíka java.net sú urèe-né na prácu so sieou atï. V balíku java.util sa nachádzaokrem mnostva ïalších tried aj trieda Vector . Jej úplnémeno je pod¾a prv uvedených pravidiel java.util.Vector .

Vráme sa ešte na chví¾u k deklarácii údajových èlenova metód tried. V prípade, e v deklarácii neuvedieme nija-ký modifikátor prístupu, bude daný èlen (èi metóda) prí-stupný v rámci tejto triedy, všetkých jej potomkov, a ajv rámci všetkých tried toho istého balíka, nebude všakprístupný mimo balíka. Typy prístupu sú v Jave teda štyri:private, protected, implicitný (takisto balíkový) prístupa public.

Implementácia balíkovKadý javovský virtuálny stroj musí vedie, ako nájs bi-nárny obraz kadej triedy na základe jej plne kvalifikova-ného mena. Jednou z najjednoduchších a súèasne naj-pouívanejších metód je prevedenie hierarchickej štruk-túry balíkov a tried do hierarchickej štruktúry adresárova súborov. Balíku java tak bude zodpoveda adresár java,ktorý musí obsahova podadresáre ako applet, awt, io,lang, net, util a pod. Obsah kadého podadresára je ekvi-valentný obsahu kadého balíka. V podadresári java/utilby sme teda mali nájs binárny obraz triedy Vector ,súbor Vector.class. Zdrojový kód kadej triedy sa zvykneumiestòova do rovnakého adresára ako jej binárny tvar,take v spomínanom podadresári nájdeme pravdepodob-ne aj súbor Vector.java. Teraz je u zrejmé, ako JVM

nájde ¾ubovo¾nú triedu – jednoducho zoberie jej plne kva-lifikované meno, bodky v òom nahradí odde¾ovaèmi adre-sárov pre danú platformu (t. j. obyèajne / alebo \, prípad-ne ešte :) a k výsledku pripojí príponu .class.

 Je oèividné, e virtuálny stroj musí vedie, kde je koreòcelej hierarchie. To sa väèšinou dozvie z premennej pro-stredia CLASSPATH. Jej obsahom býva postupnos ciestk adresárom, ktoré potom slúia ako štartovacie body nah¾adanie príslušnej triedy. Je logické, e implementácieumoòujú ma týchto koreòov nieko¾ko – potom netrebamieša štandardné javovské triedy s triedami, ktoré tvo-ria vlastný program.

Spomínaný systém ukladania tried v súborovom sys-téme má jednu drobnú nevýhodu: môe zabera pomer-ne dos ve¾a miesta na disku, pretoe ide o mnostvo

malých súborov a na niektorých systémoch v takom prí-pade dochádza k plytvaniu miestom vzh¾adom na inter-nú fragmentáciu (to vtedy, keï je ve¾kos alokaènej jed-notky zbytoène ve¾ká). Riešenie je našastie triviálne: celýstrom binárnych obrazov tried sa skomprimuje do jed-ného súboru.

Ïalším spôsobom organizácie tried je ich ukladanie do

PC REVUE 21

JAVA POD LUPOU

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 22/36

databázy. Tento spôsob pouívajú niektoré vývojové pro-stredia.

Deklarácia packageVysvetlíme si najprv pojem kompilaèná jednotka. V prípa-de ukladania tried do súborového systému je kompilaè-nou jednotkou súbor so zdrojovým textom jednej aleboviacerých tried. Kadá trieda (a pochopite¾ne aj rozhra-nie) môe by deklarovaná s modifikátorom public alebo

bez neho. Pokia¾ je trieda deklarovaná ako verejná (tedas k¾úèovým slovom public), musí sa jej zdrojový kódnachádza v súbore s rovnakým názvom, ako je menotejto triedy, a s príponou .java. Z toho vyplýva, e v ka-dej kompilaènej jednotke sa smie nachádza deklarácianajviac jednej verejnej triedy.

Verejná trieda je vidite¾ná a prístupná všetkým trie-dam z toho istého balíka, ako aj kadej triede z ¾ubo-vo¾ného iného balíka. Naproti tomu trieda deklarovanábez modifikátora public  je prístupná len v rámci svojhobalíka, mimo balíka ju pouíva nemono. Taká trieda saspráva ako privátna pre svoj balík. Jej deklaráciu monouloi do súboru s ¾ubovo¾ným názvom.

V kadej kompilaènej jednotke sa môe nachádzainformácia o tom, do ktorého balíka náleia triedy v nej

deklarované. Túto informáciu zabezpeèuje k¾úèové slovopackage, nasledované plne kvalifikovaným menom balí-ka. Ak sa deklarácia package v súbore nachádza, musíby uvedená ako prvá, ináè prekladaè ohlási chybu.

Deklaráciu package môeme aj vynecha. Robí sa toobyèajne v prípade jednoduchých èi pomocných progra-mov alebo v raných štádiách vývoja nejakého projektu.Triedy z takejto kompilaènej jednotky sa stávajú sú-èasou tzv. nepomenovaného balíka. Takto boli, mimo-chodom, definované všetky naše doterajšie triedy.

Deklarácia importPri pouití ¾ubovo¾nej triedy v programe je v zásadepotrebné uvies jej úplné meno, èo je v prípade zloitejšejbalíkovej hierarchie znaène frustrujúce. Java preto posky-tuje príkaz import, pomocou ktorého môeme poadova-né triedy sprístupni pod svojimi krátkymi menami.Tento príkaz, ak ho pouijeme, sa musí nachádza v kom-pilaènej jednotke medzi príkazom package a zaèiatkomdeklarácie tried.

Príkaz import má dva spôsoby pouitia. V prvom uve-dieme za k¾úèové slovo import plne kvalifikované menotriedy, ako napríklad:

import java.util.Vector;

Odteraz sa môeme na triedu  java.util.Vector v progra-me odvoláva pouitím výrazne kratšieho Vector .Pochopite¾ne, nie je moné takto „importova“ dve triedys rovnakým krátkym menom Vector  ani nemôeme v

danej kompilaènej jednotke deklarova inú triedu Vector .Tento spôsob takisto neumoòuje importova podbalíky– nemôeme napísa import  java.util; a poui potomzápis util.Vector .

Druhý spôsob je vhodnejší v prípade, e chceme sprí-stupni viacero tried z jedného balíka. Ak pouijemenapríklad takýto zápis:

import java.util.*;

môeme na všetky triedy balíka  java.util odkazova ichkrátkymi menami, ako Vector, Set, HashMap a pod.

V našich doterajších programoch sme pouívali prevýstup textu na obrazovku konštrukciu System.out.prin-tln(...). Šikovný èitate¾ by u mal by schopný tento zápis

analyzova a zisti, e ide o volanie metódy println() nadobjektom out, ktorý je statickým èlenom triedy System.A tu je malá nezrovnalos. O nieko¾ko riadkov vyššie smepredsa tvrdili, e triedy treba sprístupòova ich úplnýmmenom a tým je pre triedu System meno java.lang.System. Pravidlo, samozrejme, platí – okrem

 jednej malej výnimky. Triedy balíka java.lang sú nato¾kopouívané, e sa importujú automaticky – kadá kompi-laèná jednotka „obsahuje“ fiktívny príkaz import java.lang.*;.

 Jednoznaèné mená balíkovV praxi pri realizácii projektu rôznymi tímami, prípadnepri vyuívaní cudzích kniníc tried môe nasta neprí- jemná situácia, keï je potrebné do jedného programu

integrova dva balíky s rovnakými názvami. To, samo-zrejme, moné nie je, preto existuje odporúèanie, akopride¾ova balíkom jednoznaèné, unikátne mená.

Postup je jednoduchý. V rámci nášho projektu sivytvoríme hierarchiu a pomenovanie balíkov, ako sa námhodí. Potom vezmeme svoju doménovú internetovú adre-su (musíme, pochopite¾ne, nejakú ma), usporiadamev nej subdomény v opaènom poradí a výsledok pripojímena zaèiatok názvu kadého nášho balíka. Ak by tedanapríklad èasopis PC REVUE (ktorého doménová adresa jepcrevue.sk) vyvíjal nejaké javovské triedy, ich plne kvali-fikované mená by sa zaèínali reazcom sk.pcrevue.Povedzme, e by to boli triedy na prácu so zvukoma s grafikou, usporiadané do dvoch balíkov sound a gra-phics. Úplné mená týchto balíkov by teda zneli sk.pcre-

 vue.sound a sk.pcrevue.graphics.

NabudúceAby sme koneène prešli od nevyhnutnej, ale nie ve¾mizáivnej teórie k praxi, v budúcej èasti sa pozrieme nazúbky niektorému zo štandardných balíkov Java API.Dovidenia o mesiac.

11.èas : Výn imky

V kadom programe sa nachádza chyba. Mono diskuto-va, èi je táto stará programátorská axióma pravdiváalebo nie, rozhodne však poèas behu programu dochádzak situáciám, ktoré nie v súlade s predpokladaným sprá-

vaním programu. Zoberme si napríklad program, ktorýmá naformátova disketu. Takýto program môe perfekt-ne fungova s disketou v mechanike, ale èo v prípade, e je mechanika prázdna? Je neprijate¾né, aby pouívate¾ dostal správu typu  Invalid drive specification – programnamiesto ne¾útostného odchodu do binárnych veènýchlovísk musí vzniknutý chybový stav detegova a vhodneošetri. Iné príklady chybových stavov v programe: nedo-statok pamäte, nepripravenos externých zariadení,pokus o delenie nulou a pod.

Výnimky v JavePráca s chybovými stavmi je pre programátora v Javeznaène zjednodušená vïaka existencii mechanizmu tzv.výnimiek. Pojem výnimka reprezentuje akúko¾vek situá-ciu, ktorá narúša normálny beh programu a na ktorejvýskyt treba náleite reagova. Súèasne pod výnimkourozumieme konkrétny objekt (teda inštanciu triedy),ktorý nesie informáciu o vzniknutej chybe.

Kadá výnimka v Jave musí by inštanciou triedyThrowable, resp. niektorého jej potomka. Táto trieda máštandardne dve podtriedy: Error  a Exception. Výnimkytypu Error reprezentujú váne, obyèajne nenapravite¾néchyby - vnútorná chyba virtuálneho stroja, chyba pri lin-kovaní tried a pod. Od programu sa neoèakáva, e budena výnimky tohto typu reagova. Výnimky triedyException naproti tomu predstavujú bené chybovésituácie, ktoré rozumný program dokáe detegova aošetri. Od oboch tried je, pochopite¾ne, odvodená celáhierarchia ïalších, špecifických tried (napr. triedaIOException , ktorá reprezentuje chyby pri vstupno-výstupných operáciách).

Ku vzniku výnimky môe dôjs z troch príèin:1. výnimka vznikne synchrónne, pri vyhodnocovaní

výrazu, pri chybe poèas nahrávania a linkovania triedy,alebo pri vyèerpaní dostupných zdrojov (napr. pamäte)

2. výnimka vznikne ako dôsledok vykonania príkazuthrow (pomocou ktorého môe programátor vyvolavýnimku explicitne)

3. výnimka vznikne asynchrónne (obyèajne ako dôsle-dok chyby virtuálneho stroja)

Výnimky sa ïalej delia na kontrolované a nekontrolova-

né . Kadá metóda, v ktorej môe dôjs k neošetrenej kon-trolovanej výnimke, to musí explicitne oznámi vo svojejdeklarácii pomocou klauzuly throws (pozri ïalej).

Nekontrolované výnimky takto deklarova netreba – buï sa môu vyskytnú v ¾ubovo¾nom mieste programu, alebosú nato¾ko èasté, e ich deklarácia by program zbytoèneznepreh¾adòovala. Medzi nekontrolované výnimky patriavýnimky triedy Error a jej potomkov a aj výnimky triedyRuntimeException a jej potomkov. Trieda Runtime-Exception je podtriedou triedy Exception, reprezentujú-cou chyby, ku ktorým môe dôjs všeobecne poèas behuprogramu, viac-menej nezávisle od konkrétnej operácie(príklad: výnimka NullPointerException, ktorá vzniká pripokuse o dereferenciu hodnoty null).

Ošetrenie výnimiekPokia¾ v ¾ubovo¾nom mieste programu dôjde k výnimke,okamite sa ukonèí práve vykonávaný príkaz a zaène sa

h¾ada vhodný obsluný blok (v angl. origináli exceptionhandler). V prípade, e sa takýto blok nenájde v aktuálnejmetóde, táto metóda sa predèasne ukonèí a h¾adanie sapresunie do volajúcej metódy (hovoríme, e výnimka sarozšírila do volajúcej metódy). V nej pokraèuje h¾adanierovnakým spôsobom od bodu volania metódy, v ktorejvýnimka vznikla. Výnimka sa postupne šíri metódamipod¾a spätného poradia ich volania, a kým sa nenájdevhodný handler. Ak sa stane, e sa výnimka nezachytí aniv metóde main(), program oznámi výskyt neošetrenejvýnimky a predèasne sa skonèí.

Na ošetrenie výskytu výnimiek slúi príkaz try, kto-rého úplný tvar je nasledujúci:

 try {

stráený blok}catch ( form-arg  ){

ošetrenie výnimky}finally {

 finálny blok}

K¾úèové slovo try uvádza tzv. stráený blok príkazov. Zatry blokom sa nachádzajú klauzuly catch, ktoré predsta-vujú jednotlivé obsluné bloky výnimiek. Po k¾úèovomslove catch v kadom bloku nasleduje deklarácia formál-neho argumentu (presne tak isto, ako je to v deklarácii

metód), ktorý predstavuje zachytenú výnimku. Tento for-málny argument musí by typu Throwable alebo niekto-rého z jeho potomkov. Celý príkaz ukonèuje blok finally.

Mechanizmus zachytenia výnimky je nasledujúci:· Ak v bloku try nedôjde k iadnej výnimke, vykoná sa

celý tento blok a po òom všetky príkazy bloku finally.· V prípade, e sa v ktoromko¾vek bode bloku try

vyskytne výnimka, preskoèia sa všetky zvyšné príkazy apo koniec tohto bloku a zaène sa h¾ada vhodný handler.Pri h¾adaní sa porovnáva skutoèný typ vyhodenej výnim-ky s typom formálneho argumentu kadej klauzulycatch. Výnimku dokáe zachyti prvý handler, ktorého typ

 formálneho argumentu je zhodný s typom výnimky alebo je

mu nadradený (v zmysle dediènosti; platí tu ostatne rov-naké pravidlo – potomok môe vdy zastúpi predka).

· Ak sa vhodný handler nájde, inicializuje sa jeho for-málny argument inštanciou výnimky, vykoná sa telohandlera a po òom sa celý príkaz dokonèí vykonanímbloku finally.

· V prípade, e ani jeden prítomný handler nevyhovu- je, výnimka sa rozšíri „o poschodie vyššie“. No prv, ne

22 PC REVUE

JAVA POD LUPOU

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 23/36

dôjde k opusteniu aktuálnej metódy, vykonajú sa príkazybloku finally.

Ako vidno, blok finally sa vykoná za kadých okolnos-tí, preto doò obyèajne dávame „upratovacie“ príkazy,ktoré uvo¾nia alokované prostriedky a vrátia veci do kon-zistentného stavu.

Na pamäti treba ma fakt, e v prípade výskytuneošetrenej výnimky sa blok try nedokonèí a celý zvyšokmetódy sa preskoèí, pretoe dôjde k nelokálnemu skoku

do volajúcej metódy. A ak volajúca metóda výnimkunedokáe zachyti, ani ona sa nedokonèí a výnimkapokraèuje stále vyššie a vyššie. Riadenie sa programuvráti a v okamihu, keï sa nájde vhodný handler – prog-ram po spracovaní výnimky pokraèuje za tým príkazomtry, ku ktorému tento handler patrí.

V príkaze try sa nemusí nachádza nijaký obslunýblok catch. V takom prípade sa výnimka vdy rozšíri dovolajúcej funkcie, ale ešte predtým sa vykoná blok final-ly. Ak chceme blok finally vynecha (to môeme, nie jepovinný), musíme uvies aspoò jednu klauzulu catch.

Ako sme u spomínali, metóda, ktorá vie, e sa z nejmôe rozšíri nejaká výnimka, musí to explicitne dekla-rova pomocou klauzuly throws. Tá sa nachádza v dekla-rácii medzi ukonèujúcou zátvorkou zoznamu formálnychargumentov metódy a samotným telom funkcie a pozo-stáva z k¾úèového slova throws a èiarkou oddelenéhozoznamu povolených výnimiek (resp. ich tried). Pozorvšak, metóda odvodenej triedy nemôe takto deklarovaviac výnimiek ako prekrytá metóda nadradenej triedy.

V zásade mono povinnos deklarova typ vyhadzova-ných výnimiek obís tým, e do kadej metódy sa doplnídeklarácia throws Throwable, èím sa postihnú všetkymoné výnimky. Toto riešenie sa však neodporúèa,pretoe sa ním programátor dobrovo¾ne vzdáva jednej zmoností kontroly správnosti programu.

Väèšinu preddefinovaných výnimiek vyhadzujú metó-dy štandardných tried Java API. Programátor si všakmôe definova vlastné triedy výnimiek, odvodenéobyèajne od triedy Exception. Takéto vlastné výnimky(ale nielen tie) potom môe na vhodnom mieste progra-mu explicitne vyvola pomocou príkazu throw. Jeho syn-tax je jednoduchá:

 throw  výraz ;

Uvedený výraz sa musí vyhodnoti na inštanciu triedyThrowable alebo niektorej z jej potomkov. Príkaz throw je správne pouitý pri splnení aspoò jednej z nasledujú-cich troch podmienok:

1. nachádza sa v bloku try, ktorý dokáe zachyti uve-denú výnimku

2. nachádza sa v metóde, ktorá deklaruje, e môevyhodi uvedenú výnimku

3. vyhadzuje nekontrolovanú výnimku

Výrazom v príkaze throw môe by u vopred existu- júci objekt, ale najèastejšie sa príslušná inštancia výnim-ky vytvára a v okamihu jej vyhodenia, take sa obyèajnestretneme so zápisom:

 throw new Exception();

PríkladNa demonštráciu práce s výnimkami poslúi nasledujúcipríklad (je pomerne jednoduchý, zloitejší príklad nájdeèitate¾ ako vdy na webových stránkach PC REVUE):

 // TestException.javapublic class TestException extends Exception{

TestException(){ super(); }TestException(String s){ super(s); }

}

 // Exceptions.javapublic class Exceptions

{public static void main(String[] args){

for (int i = 0; i < 4; i++){ try {

 throwIt(i);System.out.println(i + ": no exception");

}catch (Exception e)

{ System.out.println(i + ": " + e.getClass()+ ": " + e.getMessage());

}}

}static void throwIt(int i) throws TestException{ try {

switch (i){case 0: i = i/i;case 1: String s = null;

i = s.length();case 2: throw new TestException("just test");default: return;}

}

finally {

System.out.println("−− throwIt(" + i + ") done −−");}

}}

Trieda TestException predstavuje našu vlastnú trieduvýnimiek. Je odvodená od triedy Exception, preto patrímedzi kontrolované výnimky. Dva (zvyèajné) konštrukto-ry len volajú konštruktory nadradenej triedy. Pri vytvore-ní inštancie výnimky je moné zada pomocný,vysvet¾ujúci text.

Metóda main() hlavnej triedy Exceptions volá metóduthrowIt() postupne s argumentom 0, 1, 2 a 3. Toto vola-nie je uzavreté do bloku try. Metóda throwIt() v závislos-ti od svojho argumentu vyvoláva rôzne typy výnimiek(prípadne aj iadnu). Všimnime si, e pomocou klauzulythrows táto metóda deklaruje len výnimku Test-Exception, ostatné dve (ArithmeticException aNullPointerException) patria medzi nekontrolované.iadna výnimka v metóde nie je ošetrená, take sa z nejrozšíri von, najprv sa však vïaka bloku finally vypíše pat-rièná správa. V metóde main() sa nachádza jediný hand-ler, ktorý zachytáva všetky výnimky typu Exception a jeho potomkov – to znamená, e zachytí èoko¾vek, èomôe „prís“ z metódy throwIt(). Úlohou handlera jevypísa informácie o výnimke pomocou jej metódgetClass() (zdedená z triedy Object – vráti triedu výnim-ky, ktorá sa v uvedenom výraze automaticky konvertuje

na reazec obsahujúci jej názov) a getMessage() (vraciadoplnkovú informáciu o výnimke, ktorú sme v prípadetriedy TestException vytvorili sami – to je ten text „justtest“). Výstup programu je takýto:

−− throwIt(0) done −−0: class java.lang.ArithmeticException: / by zero−− throwIt(1) done −−1: class java.lang.NullPointerException: null−− throwIt(2) done −−2: class TestException: just test−− throwIt(3) done −−3: no exception

Ako vidie, program sa napriek výskytu výnimoèných sta-vov neskonèil chybovým hlásením, namiesto toho výnim-ky korektne „ošetril“.

Balík java.langV druhej polovici tejto èasti a v nieko¾kých ïalšíchpokraèovaniach seriálu sa postupne prejdeme štandard-nými balíkmi Java API a ich najèastejšie pouívanými trie-dami a rozhraniami. Nie je, pochopite¾ne, moné zapo-

dieva sa na stránkach èasopisu kadou triedou podrob-ne, èitate¾ sa preto v prípade hlbšieho záujmu budemusie obráti na oficiálnu dokumentáciu k JDK. Ešteupozornenie: opis balíkov je v súlade s aktuálnou verziou JDK 1.3.1 – v prípade pouitia staršej verzie môu v doku-mentácii niektoré metódy dosia¾ „neexistova“.

Prvým na rane je balík java.lang, ktorý obsahuje trie-dy úzko súvisiace s návrhom programovacieho jazyka Java. Ve¾mi dôleitou súèasou tohto balíka je trieda

Object, priamy èi nepriamy predok ktorejko¾vek deklaro-vanej javovskej triedy. Object obsahuje nieko¾ko metód,na ktoré by mal reflektova prakticky kadý objekt.Metóda clone() slúi na vytvorenie plytkej kópie objektu(shallow copy, t. j. èlen po èlene), ale len v prípade, epríslušná trieda implementuje rozhranie Cloneable(ktoré je takisto súèasou balíka java.lang). Toto rozhra-nie neobsahuje nijaké metódy, slúi len na indikáciu, e je moné klonovanie previes. Ïalšia metóda equals()testuje zhodu objektu s ¾ubovo¾ným iným objektom.Podmienku zhody dvoch objektov si môe kadá triedadefinova sama. Metóda toString() vracia textovú repre-zentáciu objektu, getClass() vracia objekt triedy Class(poyri ïalej) nesúci informácie o triede objektu, ïalšiametóda hashCode() vypoèítava hash hodnotu objektu,ktorú pouíva napríklad údajová štruktúra Hashtable.Metódy wait(), notify() a notifyAll() slúia na implemen-táciu synchronizácie procesov a threadov – tejto témebude venovaná samostatná èas seriálu.

Ïalšia trieda Class je nosite¾om informácií o triedachprogramu. Nemá verejný konštruktor, pretoe pre kadúzavedenú triedu, rozhranie, pole, dokonca aj pre primi-tívne typy sa vytvára jedna jej inštancia automaticky.Odkaz na túto inštanciu dostaneme volaním spomínanejmetódy getClass() alebo pomocou statickej metódyClass.forName(), ktorej parametrom je názov triedy.Trieda Class obsahuje nieko¾ko metód na zisovanie typuinštancie (ako isArray(), isInstance() a pod.) a mnostvometód s názvom v tvare get...(), pomocou ktorých sa dajúzíska kompletné informácie o zloení triedy, o obsahu jej deklarácie a podobne. Ako príklad mono uvies metó-du getFields(), vracajúcu pole objektov Field opisujúcichúdajové èleny triedy. Trieda Field a ïalšie opisné triedy,ako Method èi Constructor , sa nachádzajú v podbalíku java.lang.reflect.

Trieda String predstavuje reazcový údajový typ.V porovnaní s jazykom C sa v Jave s reazcami pracujeomnoho komfortnejšie, k dispozícii je mnostvo metódna pohodlnú manipuláciu. Nové inštancie triedy Stringmono vytvori klasickým objektovým spôsobom:

String s = new String("Hello");

alebo aj takto (je to špeciálny prípad, iné objekty týmtospôsobom nevytvoríme):

String s = "Hello";

Nový reazec mono vytvori na základe iného, u exis-tujúceho reazca, alebo pomocou po¾a bajtov èi po¾a zna-kov. Metódy triedy String umoòujú sprístupòova jed-notlivé znaky (charAt()), porovnáva reazce(compareTo()), spája ich (concat()), urèova ich dåku(length()), h¾ada jeden reazec v druhom (indexOf(),lastIndexOf()), meni ve¾kos znakov (toLowerCase(),toUpperCase()) a iné. Dva reazce mono okrem metódyconcat() spoji aj pomocou operátora +:

String s = "He" + "llo";

V triede String sa nachádza mnostvo prekrytých verziístatickej metódy  valueOf(), pomocou ktorej mono pre-vádza primitívne typy na reazce. Dá sa však poui ajtakýto zápis:

double pi = 3.14159;String s = "pi = " + pi;

PC REVUE 23

JAVA POD LUPOU

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 24/36

Reazec s bude ma hodnotu "pi = 3.14159".Inštancie triedy String predstavujú reazce s nemen-

nou dåkou. V prípade, e potrebujeme reazec konštruo-va dynamicky, pridáva k nemu èi ubera z neho znaky,treba poui triedu StringBuffer . V nej nájdeme metódyako append(), delete(), insert(), replace(), substring()a podobne, ktorých funkciu azda ani netreba vysvet¾ova.

V praxi obèas nastane situácia, keï by bolo vhodné,aby sa premenná primitívneho typu správala ako objekt.

Triviálnym príkladom môe by snaha vráti z metódyviac ako jednu hodnotu, prípadne odovzda primitívnyargument metóde „odkazom“, a nie hodnotou, ako tov Jave štandardne je. Na tieto úèely nájdeme v balíku java.lang súbor tried Boolean, Byte, Character , Double,Float, Integer , Long, Short a Void. Uvedené triedy pred-stavujú objektové zapuzdrenie primitívnych typov a svýnimkou tried Boolean, Character a Void sú odvodenéod abstraktnej triedy Number . Táto trieda deklarujenieko¾ko metód s názvom v tvare  xxxValue() (kde xxx jenázov primitívneho typu), urèených na konverziu „objek-tového“ èísla na iný typ. Prakticky všetky spomínané trie-dy sa dokáu skonštruova aj na základe reazca. V prí-pade nemonosti prevodu generujú výnimkuNumberFormatException. Medzi ïalšími metódami náj-

deme compareTo() na porovnávanie zapuzdrených„èísel“, rôzne (statické) klasifikaèné metódy, akoisInfinite() èi isNaN() v triedach Float a Double, a extrém-ne uitoèné statické metódy typu parse...(), ktoré slúiana prevod reazca na èíslo (teda nie zapuzdrený objekt)príslušného typu. Príklad takéhoto prevodu:

String s = "13.98";double d; try {

d = Double.parseDouble(s);}catch (NumberFormatException e){

d = 0.0;}

(Výnimku NumberFormatException treba buï zachyti,alebo deklarova v klauzule throws obklopujúcej funk-cie.) V triede Character navyše nájdeme kolekciu klasifi-kaèných metód na zisovanie typu znakov, ako napr.isDigit(), isLetter(), isLowerCase(), isWhitespace() a iné.

Ïalšou významnou triedou balíka  java.lang je triedaMath. Nie je moné vytvára jej inštancie, všetky jejmetódy sú statické a slúia na realizáciu najrozmani-tejších matematických operácií. Ich názvy sú dostatoèneopisné: abs(), acos(), asin(), atan(), cos(), exp(), log(),max(), min(), random() (tú sme u v minulosti pouili!),round(), sin(), sqrt() èi tan().

Skupina tried Thread, ThreadGroup, ThreadLocala   InheritableThreadLocal v súèinnosti s rozhraním

Runnable nájde uplatnenie pri programovaní multithre-adových aplikácií. Ich pouitie spolu s praktickouukákou spolupráce viacerých threadov príde na radneskôr. Multithreading ostatne významne súvisí so syn-chronizáciou, pretoe paralelne beiace thready èastosúaia o prostriedky, ako èas procesora, pamä a podob-ne.

Trieda System realizuje väzbu programu na hos-tite¾ský systém. Takisto z nej nemono tvori inštancie.Trieda obsahuje tri dôleité èleny in, out, err , predstavu- júce štandardný vstup, štandardný výstup a štandardnýchybový výstup vo forme objektových prúdov, o ktorýchbude reè nabudúce. Metóda  exit() slúi na ukonèeniebeiaceho programu, currentTimeMillis() vracia aktuál-ny èas v milisekundách od polnoci 1. 1. 1970 (t. j. klasic-

ký unixový èas), getProperty()/setProperty() agetProperties()/setProperties() sprístupòujú systémovénastavenia (properties; vzdialená analógia registrov èiINI súborov), setSecurityManager() umoòuje aktiváciuzvolených bezpeènostných politík.

Trieda SecurityManager slúi na implementáciu bez-

peènostných politík. Bliší opis, ia¾, presahuje rámectohto èlánku. Trieda Runtime sprístupòuje run-time pro-stredie, v ktorom program beí. Ïalšia trieda Process sapouíva pri vytváraní natívnych procesov prostredníc-tvom metód Runtime.exec(). Inštancie triedy Packageobsahujú informácie o javovských balíkoch (názov, dodá-vate¾a, verziu a pod.).

Koneène poslednou významnou triedou balíka java.lang  je v úvode èlánku spomínaná trieda

Throwable, ktorá je rodièovskou triedou všetkých chýba výnimiek v Jave. Trieda obsahuje okrem iného metódygetMessage() a getLocalizedMessage(), vracajúce blišíopis výnimky, a metódu printStackTrace(), ktorá dokáevypísa aktuálny stav zásobníka volaných metód v oka-mihu výskytu výnimky. Podtriedy Error a Exception aniich potomkovia nijaké ïalšie metódy nepridávajú – celáhierarchia výnimkových tried slúi predovšetkým na jed-noznaènú identifikáciu vzniknutého chybového stavu.Ako sme u uviedli, trieda Error  a jej podtriedy repre-zentujú nezotavite¾né chyby, pri ktorých sa neoèakáva,e ich bude aplikácia zachytáva a ošetrova. Naprotitomu Exception a jej potomkovia indikujú výskytbených, ošetrite¾ných chýb. Z tých, s ktorými sa progra-mátor stretne najèastejšie, mono vybra

ClassNotFoundException, oznamujúcu neprítomnosbinárneho obrazu triedy, ktorej inštanciu treba vytvori,InterruptedException, ktorú je potrebné ošetrova v prí-pade pouitia metódy wait(), ïalej IOException a jej pod-triedy, ako napr. FileNotFoundException èiMalformedURLException, ktoré indikujú nejakú chybupri práci so vstupno-výstupnými triedami, ako ajmnostvo potomkov triedy RuntimeException (tú, akovieme, netreba deklarova ani zachytáva), akoArithmeticException, IllegalArgumentException,IndexOutOfBoundsException, NoSuchElementExceptionèi ob¾úbenú NullPointerException, ktorých názvy hovo-ria samy za seba.

Balík  java.lang toho obsahuje ešte o nieèo viac, aledrinu spojenú s podrobným štúdiom dokumentácie si umusí kadý programátor „oddrie“ sám. Nabudúce sapozrieme na zúbky hlavne balíku  java.io, v ktorom náj-deme triedy na realizáciu mnohých vstupno-výstupnýchoperácií. Dovidenia o mesiac.

12.èas : Vstup a výs tup údajov

V dvanástom pokraèovaní seriálu sa oboznámime s trie-dami, ktoré Java poskytuje na realizáciu vstupnýcha výstupných operácií. Na príklady, bohuia¾, tentoraznezostalo miesto, nieko¾ko ukákových programov všakmono nájs na webe PC REVUE v sekcii Programujeme.

Triedy File a FileDescriptor Trieda File navzdory svojmu menu neslúi na reprezen-táciu súborov, ale na abstraktnú, systémovo nezávislúreprezentáciu ciest k súborom a/alebo adresárom. Cestasa skladá z nepovinného prefixu (napr. \ v Unixe, C:\ alebo\\ vo Windows) a z postupnosti mien adresárov. Poslednémeno môe predstavova adresár alebo súbor. Odde¾ovaèadresárov je systémovo závislý a získa ho mono zo sta-tického èlena separator  (typu String), resp.separatorChar (typu char ) triedy File. Ïalšie dva statickéèleny, pathSeparator  a pathSeparatorChar , obsahujúznak odde¾ujúci zoznam ciest (napríklad v premennejprostredia PATH). Cesta môe by absolútna i relatívnaa môe obsahova špeciálne adresáre . a .. (t. j. aktuálnyadresár a nadradený adresár).

Konštruktory triedy File akceptujú jeden alebo dvareazcové argumenty, ktoré obsahujú cestu (pri dvochargumentoch sa cesty jednoducho spoja – ak pracujemeso súbormi v nejakom adresári, môe by vïaka tomucesta k adresáru a cesta ku konkrétnemu súboru uloenákadá v samostatnej premennej). V tretej verzii konš-

truktora mono namiesto prvého z reazcov poui inš-tanciu triedy File.

V deklarácii triedy File ïalej nájdeme nieko¾ko infor-maèných metód so samovysvet¾ujúcimi názvami:getName(), getParent(), getPath(), getAbsolutePath(),getCanonicalPath() a iné (kanonická cesta je cesta, ktoráneobsahuje adresáre . a ..). Pomocou metód canRead()a canWrite() môeme zisti, èi má program právo na èíta-nie/zápis z/do súboru. Metódy exists(), isDirectory(),

isFile(), isHidden() zisujú, èi daná cesta existuje, èireprezentuje adresár, resp. súbor a èi je skrytá (skrytácesta má vo Windows nastavený atribút Hidden, v Unixesa zaèína bodkou). Metóda lastModified() vracia èasposlednej modifikácie daného objektu, length() zase jehodåku v bajtoch.

Metóda delete() slúi na vymazanie súboru/adresára,renameTo() na ich premenovanie. Nový adresár vytvorí-me pomocou metód mkdir() alebo mkdirs(). Metódy list()a listFiles() poskytujú zoznam všetkých súborov/adresá-rov, ktoré sa nachádzajú vo vybranom adresári (tentovýber mono vhodne filtrova), pomocou metódsetLastModified() a setReadOnly() zmeníme èas posled-nej modifikácie súboru èi nastavíme príznak read-only.Statická metóda createTempFile() príde vhod, ak potre-

bujeme vytvára doèasné súbory; o ich automatické zma-zanie po skonèení programu sa postará metódadeleteOnExit().

Trieda FileDescriptor  je objektovým zapuzdrením tra-dièného súborového deskriptora (celé èíslo, identifikujúceotvorený súbor na úrovni operaèného systému).Inštanciu triedy FileDescriptor  mono získa volanímmetódy getFD() nad objektom niektorej z triedFileInputStream, FileOutputStream aleboRandomAccessFile (pozri nišie). Trieda obsahuje metó-du  valid(), ktorá zisuje platnos deskriptora súboru,a metódu sync(), ktorá vynúti synchronizáciu systémo-vých vyrovnávacích pamätí so záznamovým médiom.

I/O triedyV Jave sa vstupné/výstupné operácie realizujú podobneako v C/C++ pomocou prúdov (streams). Prúd je údajovýtok, ktorý smeruje od zdroja údajov do programu (vstup-ný prúd), resp. z programu do spotrebièa údajov (výstup-ný prúd). Zdrojom/spotrebièom údajov môe by diskovýsúbor, konzola (= klávesnica/obrazovka), IPC rúra,sieový soket a podobne. Výhodou prúdov je unifikovanýspôsob ich obsluhy. Koreòmi objektovej hierarchie I/Otried sú štyri abstraktné triedy: InputStream,OutputStream, Reader a Writer . Prvá dvojica predstavu- je spoloèný základ pre bajtové prúdy (t. j. postupnos baj-tov), druhá dvojica pre  znakové prúdy (postupnos zna-kov).

Trieda InputStreamTrieda InputStream obsahuje abstraktnú metódu read()v troch obmenách, ktorá slúi na èítanie bajtu alebo po¾abajtov zo vstupného prúdu. Odvodené triedy túto metó-du musia vhodne implementova. Ak v prúde nie súk dispozícii iadne údaje, volanie read()  je blokujúce(okrem prípadu, keï sa dosiahne koniec prúdu). Pomocoumetódy skip() mono urèitý poèet bajtov v prúde „pre-skoèi“. Metóda available() indikuje, èi sa v prúde nachá-dzajú nejaké nepreèítané dáta, a pomocou metód mark()a reset() si mono „poznaèi“ pozíciu v prúde a neskôr sak nej vráti. Túto funkènos však nemusí poskytovakadý prúd. Poslednou metódou je close(), ktorá slúi nakorektné ukonèenie práce s prúdom.

Pozrime sa teraz na potomkov triedy InputStream.

Trieda ByteArrayInputStream realizuje èítanie bajtovz bajtového po¾a. Trieda FileInputStream umoòuje sek-venène èíta bajty z diskového súboru. Argumentom jejkonštruktora je cesta k súboru (typu String alebo File).Trieda ObjectInputStream slúi na deserializáciu objek-tov – táto téma je s oh¾adom na svoju zloitos mimo roz-sahu seriálu. Pomocou triedy PipedInputStream mono

24 PC REVUE

JAVA POD LUPOU

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 25/36

vytvori rúru (pipe) na medziprocesovú (resp. medzithre-adovú) komunikáciu. Druhú stranu rúry, èo musí by inš-tancia triedy PipedOutputStream, mono zada ako argu-ment konštruktora alebo ako argument samostatnejmetódy connect(). Trieda SequenceInputStreamumoòuje zreazi dva a viac vstupných prúdov do jed-ného.

Dôleitým potomkom triedy InputStream  je triedaFilterInputStream, ktorá umoòuje pod¾a potreby filtro-

va iný vstupný prúd (ten sa jej pošle ako argument kon-štruktora). Samotná trieda FilterInputStream prepúšavšetky bajty bez zmeny, skutoènými filtrami sú a jejpotomkovia: trieda BufferedInputStream, ktorá obsahujevyrovnávaciu pamä (buffer) a tým zefektívòuje èítanieúdajov zo zdrojového prúdu, triedaPushbackInputStream, ktorej metódu unread() môemepoui na „vrátenie“ posledného naèítaného bajtu spädo prúdu, a predovšetkým trieda DataInputStream ,pomocou ktorej mono èíta z prúdu primitívne javovskétypy strojovo nezávislým spôsobom (existuje jednoznaè-né mapovanie kadého primitívneho typu na postupnosbajtov a naopak), prostredníctvom metód readBoolean(),readByte(), readUnsignedByte(), readShort(),readUnsignedShort(), readChar(), readInt(), readLong(),readFloat(), readDouble() a readUTF().

Uvedené triedy mono medzi sebou vhodne kombino-va, take ak chceme napríklad èíta hodnoty primitív-nych typov zo súboru a vyuíva pritom vyrovnávaciupamä, pouijeme nasledujúci zápis:

FileInputStream f = new FileInputStream("file.dat");BufferedInputStream b = new BufferedInputStream(f);DataInputStream d = new DataInputStream(b);

Kadý ïalší prúd slúi ako wrapper (v slovenskom pre-klade azda „zapuzdrovaè“) predchádzajúceho prúdu.S finálnym objektom d pracujeme štandardným spôso-bom.

Trieda OutputStream

Trieda OutputStream  je výstupným náprotivkom triedyInputStream. Je takisto abstraktná a obsahuje k¾úèovúmetódu write(), realizujúcu zápis bajtu alebo po¾a bajtovdo výstupného prúdu, metódu flush() na vyprázdnenieprípadnej vnútornej vyrovnávacej pamäte a metóduclose(), ktorá výstupný prúd uzavrie.

Triedy odvodené od OutputStream sú poväèšinevýstupnými ekvivalentmi potomkov triedy InputStream.Trieda ByteArrayOutputStream ako spotrebiè údajovvyuíva pole bajtov, ktoré sa dokáe dynamicky zväèšo-va. Pomocou metódy writeTo() mono toto pole odoslado iného prúdu a pomocou toByteArray() previes nasamostatný objekt typu byte[]. Trieda FileOutputStreamslúi na zápis bajtov do diskového súboru. Argumentom jej konštruktora môe by reazec, objekt triedy Filealebo objekt triedy FileDescriptor . V prvom prípademono pomocou dodatoèného argumentu špecifikova, èisa má súbor otvori v móde append (t. j. zapisované bajtysa budú pridáva na koniec u existujúceho súboru.Pomocou triedy ObjectOutputStream mono realizovaserializáciu objektov. Na vytvorenie zápisovej zlokymedziprocesovej komunikácie je k dispozícii triedaPipedOutputStream. K vytváraniu rúr na komunikáciumedzi threadmi sa ešte v seriáli vrátime pri rozprávanío threadoch – na príklade budeme demonštrova, ako sarúra vytvorí a ako sa cez òu posielajú údaje.

Aj medzi výstupnými prúdovými triedami nájdeme„filtrovaciu“ triedu FilterOutputStream. Tá sama osebeprepúša údaje bez zmeny. Medzi jej potomkov patrí trie-

da BufferedOutputStream, ktorá implementuje výstupnýprúd s vyrovnávacou pamäou, a takisto triedaDataOutputStream, pomocou ktorej mono do výstup-ného prúdu zapisova hodnoty primitívnych typov(v binárnom formáte) a reazcov – na to máme k dispozí-cii metódy  writeBoolean(),  writeByte(),  writeShort(), writeC har(), writeInt(), writeLong(), writeFloat(),

 writeDouble(), writeBytes(), writeChars() a writeUTF().Poslednou filtrovacou triedou je PrintStream, vïaka kto-rej môeme realizova zápis hodnôt primitívnych typov(a reazcov) v ¾udskom, èitate¾nom tvare, prostredníc-tvom metód print() a println(). Druhá z metód ukonèujevýpis znakom prechodu na nový riadok, èo je obyèajne'\n'. Na ilustráciu rozdielu medzi DataOutputStreama PrintStream: v prvom prípade sa èíslo 123 (nech je typubyte) zapíše do prúdu ako jeden bajt s hexadecimálnou

hodnotou 0x7B, v druhom prípade ako tri ASCII znaky 1,2 a 3, teda tri hexadecimálne hodnoty 0x31, 0x32 a 0x33.

Trieda Reader Trieda Reader  je prakticky totoná s triedou InputStream– je takisto abstraktná a obsahuje rovnaké metódy (svýnimkou metódy ready(), ktorá je však inak ekvivalent-ná metóde available()), jediným rozdielom je, e tátotrieda z prúdu èíta znaky. Tie, ako vieme, majú rozsah 16bitov, èo sú dva bajty. Trieda Reader preto plne podpo-ruje všetky unikódové znaky a nie je viazaná na vybranéosembitové kódovanie národných abecied.

Trieda Reader  má mnostvo potomkov, èiastoènepodobných potomkom triedy InputStream. Nájdeme tutak triedu CharArrayNumber , ktorá ako zdroj údajovpouíva pole znakov, triedu StringReader , ktorá podob-ným spôsobom èíta znaky z objektu typu String, i trieduPipedReader , ktorá umoòuje èítanie znakov z rúry IPC.Trieda InputStreamReader funguje ako most medzi baj-tovými a znakovými prúdmi. Argumentom jej konštruk-tora je inštancia niektorého vstupného prúdového typu,z ktorého sa bajty èítajú a prekladajú na znaky pod¾avybraného kódovania znakov. Táto trieda sa vyuije prièítaní znakov zo štandardného vstupu, pretoe statickýèlen System.in  je typu InputStream. Na zjednodušeniepráce so súbormi je od triedy InputStreamReader odvo-dená trieda FileReader , ktorá je v podstate spojenímobjektov typu InputStreamReader a FileInputStream.

Z filtrovacích tried tu nájdeme triedu FilterReader ,ktorá opätovne slúi len ako bázová trieda, a jej potomkaPushbackReader , schopného prostredníctvom metódyunread() vráti posledný naèítaný znak spä do prúdu.Ïalšia trieda BufferedReader obsahuje vnútornú vyrov-návaciu pamä, vïaka èomu môeme naraz èíta celériadky znakov – na to slúi metóda readLine(). Od triedyBufferedReader   je odvodená jej špeciálna verziaLineNumberReader , ktorá prostredníctvom metódygetLineNumber() umoòuje zisti poradové èíslo aktuál-neho riadka. Èíslovanie mono zmeni pomocou metódysetLineNumber().

Trieda Writer Posledná zo štvorice, trieda Writer , je znakovým ekviva-lentom triedy OutputStream. Obsahuje rovnaké metódy

– menovite metódu write(), ktorá slúi na zápis znaku,po¾a znakov alebo reazca do výstupného prúdu, a metó-dy flush() a close() na vyprázdnenie, resp. uzavretie prúdu.

Medzi potomkami triedy Writer logicky nájdeme trie-du CharArrayWriter , ktorá zapisuje znaky do znakovéhopo¾a (s monosou posla toto pole do iného znakovéhoprúdu pomocou metódy  writeTo() alebo ho konvertovana typ char[] pomocou metódy toCharArray()), podobnútriedu StringWriter , vyuívajúcu namiesto po¾a znakovobjekt typu String, ako aj triedu PipedWriter , ako proti-pól triedy PipedReader pri komunikácii prostredníctvomrúry. Prepojenie s bajtovými prúdmi zabezpeèuje triedaOutputStreamWriter , ktorá zapisované znaky prekladápomocou zvoleného kódovania na postupnos bajtova tie posiela na zadaný bajtový prúd. Táto trieda nájde

pre zmenu uplatnenie pri práci so štandardnými výstup-nými prúdmi System.out a System.err . Od triedyOutputStreamWriter   je odvodená trieda FileWriter ,ktorá je spojením objektov typu OutputStreamWriter a FileOutputStream.

Posledné tri triedy sú opä filtrovacie: triedaFilterWriter  (ako základ pre tvorbu vlastných filtrov),

trieda BufferedWriter , zahàòajúca vyrovnávaciu pamä,a nakoniec trieda PrintWriter , ktorá má rovnakú funkciuako trieda PrintStream, teda umoòuje prostredníctvommetód print() a println() zapisova do výstupného prúduformátovanú reprezentáciu hodnôt primitívnych typova reazcov.

Ïalšie triedy Je len málo programov, ktoré poèas svojho behu nepra-

cujú s diskovými súbormi. Triedy z predchádzajúcichodsekov, pomocou ktorých mono èíta a zapisova z/dosúborov, umoòujú len sekvenèný prístup. Pomocoumetód mark()/reset() a skip() toto obmedzenie monoaspoò èiastoène obís, ale pre pohodlnú prácu so súbor-mi tak, ako sme zvyknutí napríklad z C/C++, je to málo.Preto v Jave nájdeme samostatnú trieduRandomAccessFile, ktorá implementuje monos práceso súborom, t. j. èítanie a zápis, formou náhodného prí-stupu. Slovko náhodný v tomto kontexte, pochopite¾ne,znamená skôr ¾ubovo¾ný.

Inštanciu triedy RandomAccessFile si mono predsta-vi ako virtuálne pole bajtov, z ktorého mono èíta a doktorého mono zapisova údaje (aj za koniec súboru, lebov takom prípade sa súbor zaène jednoducho predlova).Inštancia si pamätá aktuálnu pozíciu v súbore – tú, z kto-rej sa bude nasledujúcou operáciou èíta alebo na ktorúsa bude zapisova.

Argumenty konštruktora triedy RandomAccessFile súdva: prvý typu String alebo File reprezentuje súbor,s ktorým sa bude pracova, druhý typu String udávareim práce: "r" znamená èítanie, "rw" je èítanie + zápis.Iné reimy neexistujú. Pri vytvorení inštancie sa súèasnevytvorí deskriptor súboru, objekt typu FileDescriptor ,ktorý mono získa pomocou metódy getFD().

Na univerzálne èítanie bajtov zo súboru slúia metódyread() a readFully(). Prvá z nich sa správa presne tak istoako metóda read() triedy InputStream. Druhá metódareadFully() sa od read() líši v tom, e èaká, kým nie jek dispozícii presne poadovaný poèet bajtov. MetódaskipBytes() umoòuje „preskoèi“ stanovený poèet baj-tov. Univerzálny zápis bajtov do súboru má na starostimetóda  write (), analogická metóde  write () triedyOutputStream. Na prácu s ukazovate¾om aktuálnej pozí-cie slúia metódy getFilePointer() (zistenie) a seek()(nastavenie). Zistenie a nastavenie dåky súboru zabez-peèujú metódy length() a setLength(). Súbor sa uzavrievolaním metódy close().

Metódy read() a  write() sa na pohodlnú prácu prílišnehodia. Trieda RandomAccessFile preto obsahuje rov-naké metódy typu read***() a  write***(), ako triedyDataInputStream a DataOutputStream – pozri vyššie.

V balíku java.io sa nachádza ešte jedna uitoèná trie-da, StreamTokenizer , ktorá umoòuje parsing (toto

slovo sa mi nedarí vhodne preloi – rozbor, analýzu?)vstupného údajového toku a jeho rozklad na postupnostzv. tokenov. (Èitate¾ si azda spomenie na jednu z prvýchèastí tohto seriálu, v ktorej bola reè o lexikálnych jednot-kách Javy. Postupnos lexikálnych jednotiek v zdrojovomsúbore je výborný príklad na postupnos tokenov.) Nablišie oboznámenie sa s triedou StreamTokenizer všakniet v seriáli miesta. V budúcnosti sa stretneme s po-uívanejšou triedou StringTokenizer  – tam bude k dis-pozícii aj príklad.

Výnimky a rozhraniaSpoloèným predkom všetkých výnimiek deklarovanýchv balíku java.io je trieda IOException, ktorá signalizuje,e došlo k nejakej, blišie nešpecifikovanej chybe pri I/O

operácii. Medzi jej potomkov patria triedyCharConversionException (chyba pri konverzii znakov),EOFException (pri èítaní údajov zo súboru/prúdu signali-zuje jeho koniec), FileNotFoundException (nastane pripokuse o otvorenie neexistujúceho súboru),InterruptedIOException (pri ukonèení threadu vykoná-vajúceho I/O operáciu signalizuje jej prerušenie),

PC REVUE 25

JAVA POD LUPOU

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 26/36

ObjectStreamException (bázová trieda pre výnimkytýkajúce sa serializácie objektov – sama osebe mámnostvo ïalších potomkov), SyncFailedException(chyba pri synchronizácii poèas volania metódy sync()),UnsupportedEncodingException (pokus o pouitienepodporovaného kódovania znakov) a nakoniecUTFDataFormatException (vyskytne sa pri naèítaníneplatnej UTF-8 sekvencie zo vstupného prúdu; UTF-8 je jeden zo spôsobov kódovania šestnásbitových unikódo-

vých znakov pomocou osembitových hodnôt).V balíku java.io mono nájs aj deklaráciu nieko¾kých

rozhraní: DataInput obsahuje všetky tie read***() metó-dy, ktoré implementujú triedy DataInputStream aRandomAccessFile, podobne rozhranie DataOutputobsahuje všetky metódy write***(), implementované trie-dami DataOutputStream a RandomAccessFile. Obe roz-hrania majú aj potomkov, ObjectInput a ObjectOutput,zahàòajúcich metódy pre èítanie a zápis objektov, polía reazcov. Ïalšie rozhrania Serializable, Externalizable,ObjectInputValidation a ObjectStreamConstants satýkajú serializácie objektov, no a posledné dve rozhraniaFileFilter  a FilenameFilter  obsahujú metódu accept()a pouívajú sa pri filtrovaní zoznamu súborov v metó-dach list() a listFiles() triedy File.

13.èas : Bal ík java.ut i l

V ïalšej èasti seriálu sa pozrieme, èo ponúka Java v balí-ku  java.util. Ako naznaèuje jeho názov, balík  java.utilobsahuje zbierku rozlièných uitoèných tried, prevaneúdajových štruktúr.

Údajové štruktúryPodstatnú èas balíka  java.util tvoria triedy a rozhraniatzv. kolekèného rámca (collection framework). Základomtohto rámca je šestica rozhraní Collection, List, Set,SortedSet, Map a SortedMap.

Rozhrania kolekèného rámcaRozhranie Collection reprezentuje všeobecný pojemkolekcie (zbierky) údajov. Kolekciou rozumieme ¾ubo-vo¾nú skupinu údajov, usporiadanú èi neusporiadanú. Jednotlivé údaje nazveme  prvkami danej kolekcie. Ko-lekcia môe i nemusí dovo¾ova duplicitu prvkov. Javaneposkytuje iadne triedy, ktoré by priamo implemento-vali rozhranie Collection.

Rozhranie Collection obsahuje nasledujúce metódy:size() vracia poèet prvkov v kolekcii, isEmpty() zisuje, èi je kolekcia prázdna, contains() testuje prítomnos objek-tu v kolekcii, iterator() vracia iterátor (pozri ïalej) preprístup k prvkom kolekcie, toArray() prevádza kolekciuna pole objektov, add()/remove() pridáva/odoberá prvokdo/z kolekcie, containsAll() testuje prítomnos všetkýchprvkov kolekcie v inej kolekcii, addAll()/removeAll() pri-dáva/odoberá všetky prvky kolekcie do/z inej kolekcie,retainAll() odoberá z kolekcie všetky prvky, ktoré sanenachádzajú v inej kolekcii, a clear() odstraòuje všetkyprvky z kolekcie.

Rozhranie Collection má nieko¾ko potomkov. Prvýmz nich je rozhranie List, ktoré reprezentuje  zoznam –usporiadanú postupnos údajov. Kadý prvok zoznamumá priradený celoèíselný index (èíslovanie sa zaèína odnuly). Rozhranie List pridáva nieko¾ko nových metód:get() vracia prvok na urèenej pozícii, set() nahrádzaprvok na urèenej pozícii novým prvkom, add() vkladánový prvok do zoznamu na urèenú pozíciu, remove()odoberá zo zoznamu prvok na urèenej pozícii,indexOf()/lastIndexOf() vracia index prvého/poslednéhovýskytu zadaného prvku v zozname, listIterator() vraciašpeciálny iterátor pre zoznamy a subList() vracia podzo-znam zoznamu.

Druhý potomok rozhrania Collection má názov Set

a predstavuje matematický pojem mnoiny – neusporia-dané kolekcie údajov bez duplicitných prvkov. RozhranieSet nezavádza iadne nové metódy. Má však potomka,rozhranie SortedSet, ktoré reprezentuje usporiadanú

mnoinu. Takáto mnoina má svoje prvky usporiadanébuï „prirodzeným“ spôsobom, alebo na základe objektuimplementujúceho rozhranie Comparator , obsahujúcedve metódy, compare() a equals(), ktoré vhodným spô-sobom definujú reláciu úplného (sic!) usporiadania.

V rozhraní SortedSet nájdeme zopár nových metód:comparator() vracia príslušný objekt Comparator ,subSet() vracia vybranú podmnoinu danej mnoiny,headSet() vracia všetky prvky „menšie“ ako zadanýprvok, tailSet() vracia všetky prvky „väèšie alebo rovné“ako zadaný prvok a first()/last() vracia „najmenší/naj-väèší“ prvok mnoiny.

Piate údajové rozhranie Map (nie je potomkom roz-hrania Collection) predstavuje mapu – objekt, ktorý rea-lizuje transformáciu zadaného k¾úèa na hodnotu. Mapateda obsahuje mnoinu dvojíc k¾úè-hodnota. Usporia-danie mapy je v zásade urèené usporiadaním týchto dvo- jíc (presnejšie poradím, v akom sú tieto dvojice sprístu-pòované iterátormi).

Rozhranie Map obsahuje nieko¾ko metód významovo

zhodných s metódami rozhrania Collection, menovitesize(), isEmpty(), clear(), a ïalej vlastné špecifické metó-dy: containsKey() testuje prítomnos zadaného k¾úèa,containsValue() testuje prítomnos zadanej hodnoty,get() vracia hodnotu patriacu zadanému k¾úèu, put() pri-raïuje zadanému k¾úèu hodnotu, remove() odstraòujek¾úè z mapy, putAll() kopíruje do mapy všetky dvojicek¾úè-hodnota z inej mapy, keySet() vracia mnoinu všet-kých k¾úèov (ako objekt typu Set),  values( ) vraciamnoinu všetkých hodnôt (ako objekt typu Collection)a entrySet() vracia mnoinu všetkých dvojíc (ako objekttypu Set). Dvojice k¾úè-hodnota, ktoré vracia poslednáz vymenovaných metód, sú typu Map.Entry, èo je static-ké rozhranie deklarované v rozhraní Map. Na prácus dvojicami toto rozhranie poskytuje metódy getKey(),setKey() a setValue() so samovysvet¾ujúcimi názvami.

Posledným údajovým rozhraním je SortedMap, tedausporiadaná mapa. Usporiadanie sa týka k¾úèov a je po-dobne ako pri usporiadanej mnoine dané buï „prirodze-ne“, alebo prostredníctvom objektu typu Comparator .Nové metódy triedy SortedMap: comparator() vraciazadaný komparátor, subMap() vracia vybranú podmapudanej mapy, headMap() vracia èas mapy obsahujúcuk¾úèe menšie ako zadaný k¾úè, tailMap() vracia èas mapyobsahujúcu k¾úèe väèšie alebo rovné ako zadaný k¾úè afirstMap()/lastMap() vracia najmenší/najväèší k¾úè mapy.

Iterátory Iterátory sú údajové metaštruktúry, ktoré umoòujú

k prvkom kolekcie pristupova opakovane, v jednotlivýchiteráciách cyklu. Balík  java.util deklaruje dve iteraènérozhrania.

Prvé z nich, Iterator , sa pouíva pri iterovanom prí-stupe ku kolekciám. Obsahuje tieto metódy: hasNext()testuje, èi mono sprístupni ïalší prvok, next() sprístup-ní ïalší prvok a remove() odstráni prvok, vrátený posled-ným volaním next(), z kolekcie.

Druhé rozhranie, ListIterator , je potomkom rozhraniaIterator a poskytuje iterovaný prístup k prvkom zozna-mu. Obsahuje nieko¾ko ïalších metód: hasPrevious() tes-tuje, èi mono sprístupni predchádzajúci prvok,previous() sprístupní predchádzajúci prvok,nextIndex()/previousIndex() vracia index prvku, ktorý bybol sprístupnený nasledujúcim volaním next()/pre-

 vious(), set() nahrádza prvok vrátený posledným volanímnext()/previous() novým prvkom a koneène add() pridávado zoznamu nový prvok, pred prvok, ktorý by bol vrátenýnasledujúcim volaním next() a za prvok, ktorý by bol vrá-tený nasledujúcim volaním previous().

K prvkom zoznamov tak mono pristupova buï ná-hodným spôsobom, pomocou ich indexov, alebo s

pouitím iterátorov, ktoré implementujú sekvenèný prí-stup. Príklad oboch spôsobov nájde èitate¾ na webovejstránke PC REVUE.

Triedy kolekèného rámcaV balíku  java.util sa okrem uvedených rozhraní nachá-dzajú aj ich rozlièné implementácie.

Trieda AbstractCollection predstavuje skelet preimplementáciu rozhrania Collection. Slúi ako bázová

trieda dvom ïalším triedam, AbstractList a AbstractSet.Tieto dve triedy sú analogicky skeletmi pre implementá-cie rozhraní List a Set. Do poètu chýba u len triedaAbstractMap, ktorá predstavuje skeletálnu implementá-ciu rozhrania Map.

Pozrime sa teraz na potomkov triedy AbstractList.Prvým z nich je ïalšia abstraktná triedaAbstractSequentialList. Aj táto trieda predstavuje kostrupre implementáciu rozhrania List, ale na rozdiel od trie-dy AbstractList, vhodnejšej na náhodný prístup k prv-kom prostredníctvom indexu (takéto zoznamy sú obyèaj-ne implementované pomocou po¾a), je triedaAbstractSequentialList šitá na mieru sekvenènému prí-stupu pomocou iterátorov. Triedy od nej odvodené môuna implementáciu poui napríklad zreazený zoznam.

 Jedným takýmto potomkom je trieda LinkedList, ktorárealizuje dvojito zreazený zoznam. Vïaka nieko¾kým pri-daným metódam ju mono efektívne poui na imple-mentáciu zásobníka, frontu i obojstranného frontu. Ide otieto metódy: getFirst()/getLast() vracia prvý/poslednýprvok zoznamu, removeFirst()/removeLast() odstraòujea vracia prvý/posledný prvok zoznamu a addFirst()/addLast() pridáva nový prvok na zaèiatok/koniec zozna-mu.

Ïalším potomkom triedy AbstractList  je triedaArrayList. Z jej názvu mono vydedukova, e ide o spo-mínanú implementáciu zoznamu pomocou po¾a. Kadáinštancia triedy ArrayList má svoju kapacitu, ktorá sazadáva ako argument konštruktora. V prípade, e sa celákapacita po¾a zaplní prvkami zoznamu, pole sa automa-ticky zväèšuje. Okrem známych metód nájdeme v triedeArrayList dve nové metódy: trimToSize() zmenší kapaci-tu po¾a tak, aby bola rovná aktuálnej dåke zoznamua  ensureCapacity() explicitne zväèší kapacitu po¾a napoadovanú ve¾kos.

Nasledujúca trieda Vector  (ešte stále hovoríme o po-tomkoch triedy AbstractList) je okrem malých detailovv zásade zhodná s triedou ArrayList. Dôvodom tejto dup-licity je skutoènos, e trieda Vector  je súèasou Javyprakticky „od zaèiatku“ a a od verzie 1.2 bola upravenátak, aby zapadla do kolekèného rámca. Vïaka tomu obsa-huje oproti triede ArrayList aj nieko¾ko vlastných metód:copyInto() kopíruje prvky vektora do externého po¾a,setSize() nastaví poadovanú ve¾kos vektora (ak treba,

dopåòa prvky s hodnotou null, prípadne odstraòuje nad-bytoèné prvky), capacity() vracia aktuálnu kapacitu vek-tora, elements() vracia prvky vektora ako enumeráciu(pozri ïalej), elementAt() vracia prvok na danej pozícii,firstElement()/lastElement() vracia prvý/posledný prvokvektora, setElementAt() nastavuje hodnotu prvku nadanej pozícii, removeElementAt() odstraòuje prvok nadanej pozícii, insertElementAt() vkladá nový prvok dovektora na poadovanú pozíciu, addElement() pridávaprvok na koniec vektora, removeElement() odoberápoadovaný prvok z vektora a koneèneremoveAllElements() odstraòuje z vektora všetky prvky.

Vsuvka: enumerácia  je objekt, ktorý dokáe postupneposkytova objekty z nejakej skupiny. Takýto objekt musíimplementova rozhranie Enumeration, ktoré obsahuje

dve metódy: hasMoreElements(), testujúcu, èi je k dispo-zícii ešte nejaký prvok, a nextElement(), vracajúcu nasle-dujúci prvok skupiny.

Trieda Vector  má jedného potomka – triedu Stack,implementujúcu zásobník, t. j. údajovú štruktúru s LIFOstratégiou prístupu. Na zjednodušenie práce táto triedaposkytuje nasledujúce metódy:   empty() testuje, èi je

26 PC REVUE

JAVA POD LUPOU

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 27/36

zásobník prázdny, peek() vracia objekt na vrchole zásob-níka, pop() odstráni objekt z vrcholu zásobníka a vraciaho volajúcej metóde, push() vkladá objekt do zásobníkaa search() vracia pozíciu daného objektu v zásobníku.

To¾ko k zoznamom, pozrime sa na potomkov triedyAbstractSet, triedy HashSet a TreeSet. Prvá z nich,HashSet, je implementáciou mnoiny, zaloenou nahešovacej tabu¾ke. V konštruktore triedy mono zadapoèiatoènú kapacitu i faktor vyaenia tabu¾ky. Druhá

trieda TreeSet implementuje usporiadanú mnoinu (t. j.SortedSet) pomocou tzv. Red-Black stromu.

Aby bol kolekèný rámec úplný, zostáva ešte spomenúpotomkov triedy AbstractMap. Tými sú triedy HashMap,TreeMap a WeakHashMap. Prvá z nich predstavuje mapuzaloenú na hešovacej tabu¾ke. Podobne ako pri HashSetmono zada poèiatoènú kapacitu aj faktor vyaeniatabu¾ky. Trieda TreeMap realizuje usporiadanú mapupomocou Red-Black stromu. Tretia z tried,WeakHashMap, je variantom triedy HashMap s tzv. sla-bými k¾úèami – v prípade, e sa niektorý k¾úè mapy unepouíva (mimo mapy naò neukazuje iadna premen-ná), bude spolu so svojou asociovanou polokou z mapyodstránený.

Iné triedyMedzi triedami realizujúcimi údajové štruktúry nájdemev balíku  java.util aj také, ktoré nie sú navrhnuté akosúèas kolekèného rámca (predovšetkým preto, e sústaršie). Ide o triedy BitSet, Dictionary, Hashtablea Properties.

Trieda BitSet predstavuje vektor bitov (bitovú mno-inu), ktorý dokáe pod¾a potreby meni svoju ve¾kos. Jednotlivé bity (hodnoty typuboolean) sú prístupné pomo-cou celoèíselného indexu. Trieda obsahuje tieto metódy:length() vracia „logickú“ dåku vektora, t. j. index najvy-ššieho nastaveného bitu + 1, set() nastavuje vybraný bit,clear() nuluje vybraný bit, andNot() vynuluje všetky bity,ktoré sú jednotkové v inej bitovej mnoine, get() vraciahodnotu vybraného bitu, and()/or()/xor() vykoná logickúoperáciu AND/OR/XOR s inou bitovou mnoinou a size()vracia poèet bitov v mnoine.

Ïalšia trieda Dictionary  je abstraktná a predstavujeúdajovú štruktúru schopnú mapova k¾úèe na hodnoty.Povauje sa za zastaranú – na odvodzovanie nových triedsa odporúèa poui rozhranie Map. Jej potomok, triedaHashtable, bola podobne ako Vector upravená tak, abyimplementovala rozhranie Map. Vzah medzi Hashtablea HashMap  je zhruba rovnaký ako medzi Vector  aArrayList.

Trieda Properties  je odvodená od Hashtable a repre-zentuje perzistentnú mnoinu tzv. vlastností (to súv podstate opä dvojice k¾úè-hodnota, kde hodnoty sútypu String). Parametrom konštruktora triedy Properties

môe by iná inštancia tejto triedy – ako „implicitný“zoznam vlastností – ktorá sa preh¾adá v prípade neús-pešného h¾adania k¾úèa v primárnom zozname. Novémetódy triedy: setProperty()/getProperty() nastavuje/vracia hodnotu vybranej vlastnosti, load() naèíta zoznamvlastností zo vstupného prúdu, store() zapíše zoznamvlastností do výstupného prúdu, propertyNames() vraciaenumeráciu všetkých k¾úèov v zozname a list() vypíšecelý zoznam na zadaný výstupný prúd. Trieda Propertiessa pouíva aj pri práci so systémovými vlastnosami JVM.

Posledné dve triedy balíka  java.util, ktoré súvisias údajovými štruktúrami, sú triedy Arrays a Collections.Obe obsahujú výhradne statické metódy, urèené na prácus po¾ami a s kolekciami. Trieda Arrays poskytuje tietometódy: sort() usporiada pole alebo jeho èas buï vzo-

stupne, na základe „prirodzeného“ usporiadania, alebopod¾a objektu typu Comparator , binarySearch() slúi nabinárne vyh¾adanie hodnoty v (usporiadanom!) poli,equals() porovnáva dve polia, fill() vyplní pole alebo jehoèas zadanou hodnotou a asList() vráti pole vo formeobjektu typu List.

V triede Collections nájdeme metódy   sort(),

binarySearch(), fill(), ktoré sú zoznamovým ekvivalen-tom rovnakých metód triedy Arrays, a ïalej tieto metó-dy: reverse() obráti poradie prvkov v zozname, shuffle()vyrobí náhodnú permutáciu prvkov zoznamu, copy() sko-píruje jeden zoznam do druhého, min()/max() vracia naj-menší/najväèší prvok zoznamu, unmodifiableXXX()/synchronizedXXX(), kde XXX je jedno zo šiestich kolekè-ných rozhraní, vracia nemodifikovate¾nú/synchronizova-nú verziu príslušnej údajovej štruktúry, singleton()/

singletonList()/singletonMap() vracia mnoinu/zoznam/mapu obsahujúcu len zadaný objekt, nCopies() vraciazoznam pozostávajúci z poadovaného poètu kópií zada-ného objektu, reverseOrder() vracia komparátor špecifi-kujúci obrátené usporiadanie k prirodzenému usporiada-niu a nakoniec   enumeration() vracia enumeráciu naddanou kolekciou.

Dátum a èasÏalším okruhom, ktorý balík  java.util pokrýva, sú triedyna prácu s dátumovými a èasovými údajmi.

Trieda Date reprezentuje èasový bod (urèený dátu-mom a èasom) univerzálneho èasu UTC s presnosou namilisekundy. Má dva konštruktory – prvý bez argumen-tov vytvorí objekt reprezentujúci aktuálny systémovýèas, druhý akceptuje jeden argument typu long, ktorýudáva poèet milisekúnd od polnoci 1. 1. 1970 GMT (ïalej„unixový èas“). Metódy triedy: getTime() vracia ekviva-lentný unixový èas, setTime() umoòuje nastavi objektDate na základe unixového èasu, before() testuje, èi saèasový bod nachádza  pred iným èasovým bodom, after()podobne testuje, èi sa èasový bod nachádza za iným èaso-vým bodom a compareTo() porovnáva èasový bod s inýmèasovým bodom. Metóda toString(), zdedená z triedyObject, konvertuje dátum/èas na reazec tvaru:

Sun Jul 22 20:07:47 GMT+02:00 2001.V benom ivote sa èasové údaje vyjadrujú pomocou

rokov, mesiacov, dní, hodín, minút a sekúnd. Na konver-ziu medzi takýmto vyjadrením a objektom typu Dateslúi abstraktná trieda Calendar  a jej potomokGregorianCalendar , reprezentujúci gregoriánsky kalen-dárny systém. Opis týchto dvoch tried a práce s nimi byzabral pomaly aj samostatný èlánok, preto sa uspokojímes uvedením najdôleitejších metód: getTime() vraciaekvivalentný objekt   Date, setTime() nastaví dátum/èasna základe zadaného objektu Date, get() vracia vybranúzloku dátumu/èasu, set() umoòuje nastavi vybranúzloku dátumu/èasu, before()/after() sa správajú podob-ne ako v triede Date, add() umoòuje posun èasovéhobodu o zadaný interval, roll()  je podobná metóde add(),nemení však hodnotu „vyšších“ zloiek. Na ilustráciu roz-dielu medzi add() a roll(): posunom dátumu 1. 11. 2001o tri mesiace dopredu pomocou add() dostaneme dátum1. 2. 2002, posunom pomocou roll() dátum 1. 2. 2001 (t. j.

zmenil sa len mesiac).S dátumom a èasom èiastoène súvisia aj ïalšie triedy:TimeZone, SimpleTimeZone a Locale. Prvé dve z nichslúia na opis èasových zón, vyjadrený odchýlkou odGMT (do úvahy sa berie aj letný èas, DST) – Simple-TimeZone  je implementáciou abstraktnej triedy Time-Zone. Tretia trieda Locale reprezentuje národné prostre-dia s kódmi pod¾a štandardu ISO. Ich bliší opis by bolistotne zaujímavý, ale, bohuia¾, nemáme naò miesto.

Ostatné triedyZo zvyšných tried v balíku  java.util medzi dôleitejšiepatria ešte triedy Observable, Random, StringTokenizer ,Timer a TimerTask.

Trieda Observable predstavuje základ pre objekty,

ktoré z nejakého dôvodu chceme pozorova a v okamihuzmeny ich stavu o tom upozorni iné objekty. „Po-zorovacie“ objekty musia implementova rozhranieObserver , obsahujúce jedinú metódu update(), ktorá savyvolá ako reakcia na zmenu pozorovaného objektu.Medzi metódy triedy Observable patria: addObserver()/deleteObserver() pridáva/odoberá pozorovate¾ov,

notifyObservers() „obvolá“ všetkých pozorovate¾ov aoznámi im, e sa stav pozorovaného objektu zmenil,setChanged()/clearChanged() nastavuje/mae príznakzmeny objektu, hasChanged() indikuje, èi sa objekt zme-nil, a countObservers() vracia poèet aktuálne pripoje-ných pozorovate¾ov.

Inštancie triedy Random generujú prúd pseudonáhod-ných èísel. Na získanie náhodného èísla poadovanejbitovej šírky slúi metóda next() a nieko¾ko jej variantov,

ktoré dokáu vráti náhodné èíslo zadaného typu, prí-padne aj so zadaným rozdelením (rovnomerné, normál-ne).

Trieda StringTokenizer  sa pouíva na „rozbitie“reazca na postupnos tokenov. Pri konštruovaní monozada odde¾ovaèe, implicitne sa predpokladajú bieleznaky. StringTokenizer  implementuje rozhranieEnumeration, nájdeme v nej teda metódyhasMoreElements() a nextElement() (vracia typ Object),ako aj vlastné metódy hasMoreTokens(), nextToken()(vracia typ String) a countTokens(). Názvy metód súsamovysvet¾ujúce.

Posledné dve triedy Timer  a TimerTask slúia naimplementáciu plánovaèa úloh. Ich èinnos èiastoènesúvisí s threadmi, preto ich zatia¾ preskoèíme. V budúc-nosti sa k nim ešte vrátime.

VýnimkyV balíku  java.util nájdeme deklaráciu nieko¾kých výni-miek. Z tých podstatných vyberáme: Concurrent-ModificationException indikuje pokus o súèasnú modifi-káciu údajovej štruktúry dvoma rôznymi threadmi,EmptyStackException sa vyskytne pri snahe vyberaúdaje z prázdneho zásobníka, NoSuchElementExceptiondostaneme pri pokuse o sprístupnenie neexistujúcehoprvku enumerácie.

14.èas: Bal íky java.ut i l* a java.net

Opis balíka java.util by nebol úplný, keby sme vynechali jeho dva podbalíky  java.util.zip a  java.util.jar . Tretímbalíkom, ktorému sa v tomto èísle pozrieme na zúbky, je java.net.

Balík java.util.zipTento balík v zhode so svojím názvom obsahuje triedypre èítanie a zápis štandardných súborov ZIP a GZIP, trie-dy pre kompresiu a dekompresiu dát pomocou algoritmu DEFLATE (pouitého v súboroch ZIP a GZIP) a nakoniectriedy pre výpoèet kontrolného súètu pod¾a algoritmovCRC-32 a  Adler-32 (špecifikácie formátov a algoritmovmono nájs v dokumentoch RFC 1950-1952).

Zaèneme od konca. Triedy Adler32 a CRC32 slúia navýpoèet kontrolného súètu postupnosti bajtov. Prácas nimi spoèíva v opakovanom volaní metódy update(),ktorej argumentom je bajt alebo pole bajtov. Po odoslanívšetkých bajtov postupnosti získame kontrolný súèetmetódou   getValue(). Tretia metóda reset() kontrolnýsúèet „reštartuje“ na úvodnú hodnotu a dovo¾uje tak opä-tovne poui existujúcu inštanciu triedy. Schéma pouitiaoboch tried vyzerá pribline takto:

CRC32 crc = new CRC32(); while ( ... ){ byte b = ... ;crc.update(b);

}

long chksum = crc.getValue();

Triedy implementujú rozhranie Checksum, ktoré obsahu- je všetky uvedené metódy.

Dve ïalšie triedy CheckedInputStream a Checked-OutputStream predstavujú vstupný, resp. výstupný prúds pridanou schopnosou poèíta kontrolný súèet dát,

PC REVUE 27

JAVA POD LUPOU

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 28/36

ktoré ním prechádzajú. Obe triedy sú odvodené od „fil-traèných“ tried FilterInputStream a FilterOutputStream(pozri predminulú èas seriálu) a navyše obsahujú metó-du getChecksum(), ktorá vracia aktuálnu hodnotu kon-trolného súètu.

Kompresiu dát pouitím populárnej kninice  ZLIB

zabezpeèuje trieda Deflater . Metódami setDictionary(),setStrategy() a  setLevel() môeme nastavi poèiatoènýslovník, komprimaènú stratégiu a úroveò kompresie

(trieda Deflater  obsahuje nieko¾ko preddefinovanýchúrovní vo forme statických konštánt). Údaje, ktoré chce-me komprimova, posielame triede pomocou metódysetInput(), skomprimované údaje získame volaním metó-dy deflate(). Pomocou metódy needsInput() zistíme, èitreba doda ïalšie vstupné údaje, metódou finish() ozná-mime triede, e u staèilo, ïalšie údaje jej nedodáme,a aby kompresiu vhodne ukonèila. Tento stav indikujemetóda  finished() vrátením hodnoty true. Vïaka metó-dam getTotalIn(), getTotalOut() a getAdler() máme k dis-pozícii celkový poèet bajtov, ktoré „pretiekli“ triedou,a ich kontrolný súèet ( Adler-32). Koneène metódy reset()a  end() slúia na reinicializáciu, resp. ukonèenie práces triedou Deflater .

Opaènú operáciu, dekompresiu dát, má na starosti

trieda Inflater . Aj tu vstupné údaje zadávame pomocoumetódy setInput(), ich dekomprimovanú podobu získa-me volaním metódy inflate(). Na zadanie poèiatoènéhoslovníka pouijeme metódu setDictionary() (èi je to nevy-hnutné, zistíme metódou needsDictionary()). MetódyneedsInput(), finished(),  getTota lIn(), getTotalOut(),getAdler(), reset() a end() majú rovnaký význam ako pripredošlej triede. Èi vo vstupnom bufferi po dekompresiizostali nejaké nespracované dáta, zistíme pomocoumetódy getRemaining().

Triedu Deflater  pouijeme obyèajne takýmto spôso-bom:

Deflater dft = new Deflater(); byte[] data = new byte[...];

 byte[] cdata = new byte[...];...dft.setInput(data);dft.finish();dft.deflate(cdata);

a triedu Inflater zase takto:

Inflater ift = new Inflater();ift.setInput(cdata);ift.inflate(data);

Triedy Deflater  a Inflater  sú vhodne skombinované sovstupnými/výstupnými prúdmi v triedach Deflater-OutputStream a InflaterInputStream (opä sú to „filtraè-né“ triedy). Prvá z oboch tried disponuje schopnosoupriebene komprimova údaje zapisované pomocou štan-

dardnej metódy  write(), druhá, naopak, dokáe dekom-primova údaje èítané pomocou metódy read(). Na detek-ciu konca vstupného prúdu InflaterInputStream po-uijeme metódu available().

Štvorica tried ZipEntry, ZipFile, ZipOutputStreama ZipInputStream znaèným spôsobom u¾ahèuje prácu sosúbormi ZIP. ZipEntry reprezentuje jeden poloku súbo-ru ZIP (t. j. jeden zo súborov v archíve). Kadá poloka másvoje meno, ktoré sa zadáva ako argument konštruktoraa zisti ho mono pomocou metódy getName(). Ïalšiemetódy triedy ZipEntry slúia na nastavenie/sprístupne-nie rôznych atribútov poloky: setTime(), setSize(),setCompressedSize(), setCrc(), setMethod(), setExtra(),setComment() a ich get***() ekvivalenty – názvy metód súdostatoène opisné. Pomocou metódy isDirectory() zistí-me, èi je daná poloka adresárom (názvy adresárov sakonèia znakom /).

Ïalšia trieda ZipFile slúi na èítanie poloiek zo súbo-ru ZIP. Argumentom jej konštruktora je reazec s cestouk súboru alebo objekt triedy File. Cestu k súboru môemespolu s menom zisti dodatoène volaním metódy

getName(). Metóda size() vracia poèet poloiek v súbore,metóda   entries() vracia poloky ako enumeráciu (typEnumeration). Pomocou getEntry() sa dostaneme k vy-branej poloke a pomocou getInputStream() získamevstupný prúd, ktorý mono poui na èítanie údajovz poloky. Metóda close() otvorený súbor korektne uza-vrie.

Trieda ZipOutputStream  je potomkom Deflated-OutputStream a predstavuje výstupný prúdový filter na

zápis do súborov ZIP. Komprimaènú metódu, úroveòkompresie a prípadný komentár môeme špecifikovapomocou metód setMethod(), setLevel() a setComment().Novú poloku v súbore ZIP zaèneme metódouputNextEntry(). Zápis sa realizuje klasickou metódouwrite(), poloku uzavrieme volaním metódy closeEntry().Súbor (a prúd) uzavrieme metódou close().

Komplementárna trieda ZipInputStream slúi akovstupný filter na èítanie zo súborov ZIP. Je potomkomtriedy InflaterInputStream a pracuje sa s òou podobneako s predchádzajúcou triedou: nasledujúcu poloku„zaèneme“ volaním getNextEntry(), èítanie obsahupoloky obstará metóda read() a poloku nakoniec uza-vrieme metódou closeEntry(). Metóda createZipEntry()slúi na vytvorenie objektu ZipEntry pre poloku so

zadaným menom.Posledné dve triedy, GZIPOutputStream a

GZIPInputStream, predstavujú prúdové filtre pre zápisa èítanie do/z GZIP súborov. Tie nemajú iadnu vnútornúštruktúru (preto sa v UNIX-like operaèných systémochmusí poui najprv TAR archivátor), take sú predefino-vané len metódy read() a write() (triedy sú odvodené odDeflaterOutputStream a InflaterInputStream).

Balík  java.util.zip obsahuje aj dve triedy výnimiek:DataFormatException, ktorá signalizuje chybu formátuúdajov pri ich rozba¾ovaní, a ZipException, ktorá indiku- je chybu pri práci so súborom ZIP.

Balík java.util.jar Druhý podbalík poskytuje triedy pre prácu so súbormi JAR (= Java ARchive), ktoré sú zaloené na štandardnomformáte ZIP a navyše volite¾ne obsahujú tzv. manifestaè-ný súbor (manifest file, ïalej len „manifest“). Tento súborobsahuje metainformácie o obsahu súboru JAR vo formepoloiek a k nim priradených mnoín atribútov (pod atri-bútom treba rozumie dvojicu k¾úè-hodnota).

Upozornenie: nasledujúce riadky budú èitate¾ovi omno-ho jasnejšie po preštudovaní dokumentácie k JDK, kde sanachádza opis súborov JAR i manifestu.

Prvou z tried balíka  java.util.jar  je Attributes, ktoráfunguje podobne ako mapovacie triedy balíka java.util –mapuje názvy atribútov na reazcové hodnotypridruené k nim (trieda Attributes v skutoènosti imple-mentuje rozhranie  java.util.Map). Hodnotu vybraného

atribútu zistíme pomocou metódy getValue(). Meno atri-bútu môeme zada ako reazec alebo ako objekt typuAttributes.Name, èo je pomocná trieda na reprezentáciunázvov atribútov s mnostvom preddefinovaných static-kých konštánt (blišie pozri dokumentáciu k JDK).Opaènú operáciu – nastavenie hodnoty atribútu – reali-zuje metóda putValue(). Ostatné metódy boli opísanév predchádzajúcej èasti.

Samotný manifest reprezentuje trieda Manifest.Pomocou metódy getMainAttributes() získame tzv. hlav-né atribúty manifestu (týkajú sa celého manifestu) apomocou getAttributes() sa dostaneme k atribútom jed-notlivých poloiek. Zoznam poloiek (objekt typu Map)získame volaním metódy getEntries(). Metóda clear()zruší celý obsah manifestu, metódy read() a  write()

slúia na naèítanie/zápis obsahu manifestu z/do zada-ného prúdu.Nasledujúce štyri triedy –  JarEntry ,  JarFile,

 JarOutputStream a JarInputStream – sú významom prak-ticky totoné so svojimi náprotivkami v balíku java.util.zip(ba èo viac, sú ich potomkami). Trieda  JarEntry reprezen-tuje poloku súboru JAR (pozor, nie poloku manifestu!)

a obsahuje navyše metódu getAttributes() , ktorá vraciaatribúty danej poloky, a getCertificates() – tá vracia digi-tálne certifikáty poloky.

Trieda  JarFile slúi na èítanie obsahu súboru JAR. Jemoné prikáza, aby sa pri otváraní súboru skontroloval jeho digitálny podpis. Medzi pridanými metódami nájde-me getManifest() na prístup k manifestu súboru JAR a getJarEntry() na sprístupnenie zadanej poloky súboru.

Triedy  JarOutputStream a  JarInputStream celkom

logicky slúia ako prúdové filtre na zápis/èítanie súborov JAR. V prvej triede,  JarOutputStream, nenájdeme niènové, len predefinovanú metódu putNextEntry(). Druhátrieda,  JarInputStream, obsahuje dve nové metódy:getManifest() a getNextJarEntry(). Ich význam je zrejmý.

V balíku  java.ut il.jar  nájdeme jednu výnimku, JarException, odvodenú od ZipException a indikujúcuproblémy pri èítaní alebo zápise súboru JAR.

Balík java.netZ názvu tohto balíka je na prvý poh¾ad jasné, e budeobsahova triedy pre podporu sieových aplikácií.Komunikácia sa realizuje prostredníctvom soketov – Javamlèky predpokladá prítomnos TCP/IP (èo je však úplnelogické, majorita súèasných sietí pouíva protokoly rodi-

ny TCP/IP).Na reprezentáciu adries IP (protokolu IPv4) je k dispo-

zícii trieda InetAddress. Èo je zvláštne, táto trieda nemánijaký konštruktor (teda aspoò nie verejne prístupný), navytvorenie objektu typu InetAddress treba poui jednuzo statických metód getLocalHost(), getByName(),getAllByName(). Prvá z metód vracia objekt reprezentu- júci lokálnu adresu IP, druhá a tretia vracajú objekt, resp.pole objektov predstavujúcich jednu adresu IP alebomnoinu všetkých moných adries IP poèítaèa špecifiko-vaného pomocou reazca s doménovým menom alebos adresou IP v bodkovom zápise (ako napr. "195.168.1.4").

Medzi ïalšie metódy triedy InetAddress patria:isMulticastAddress() – slúi na rozpoznanie multicastadries (to sú adresy triedy D, zaèínajúce sa bitmi 1110),getHostName() – vracia doménové meno patriace k danejadrese IP, getHostAddress() – vracia adresu IP akoreazec v bodkovom zápise a getAddress() – vracia adre-su IP ako pole štyroch bajtov.

Význam triedy URL je zrejmý. Na zopakovanie: URL (=Uniform Resource Locator) predstavuje spôsob, ako nainternete mono odkazova na rôzne prostriedky (akonapr. stránky, súbory, mailové schránky). URL pozostávazo špecifikácie protokolu, názvu cie¾ového poèítaèa, voli-te¾ného èísla portu, na ktorom prebieha komunikácia,a cesty, ktorá jednoznaène identifikuje prostriedok.Trieda URL obsahuje viacero konštruktorov, novú inštan-ciu mono zostroji napríklad takto:

URL url = new URL("http", "www.niekde.sk", 80,

"/index.htm");

ale aj takto:

URL url = new URL("http://www.niekde.sk:8080/index.htm");

Metódy getQuery(), getPath(), getUserInfo(),getAuthority(), getPort(), getProtocol(), getHost(),getFile() a getRef() vracajú rozlièné zloky URL (podquery sa rozumie èas cesty za prípadným znakom ?, aut-hority je zloenina host:port , resp. user@host:port , a ref  jeèas cesty za prípadným znakom #). Metódou sameFile()môeme zisova zhodu dvoch URL s vylúèením zlokyref. Pomocou metódy toExternalForm() získame URLv tvare súvislého reazca. Dôleitá metódaopenConnection() vráti objekt URLConnection (pozriïalej), ktorý reprezentuje sieové spojenie so zadanýmURL. Podobne metóda openStream() vytvorí spojenies URL a vráti vstupný prúd na èítanie z tohto spojenia.Pomocou metódy getContent() získame obsah URL voforme javovského objektu.

28 PC REVUE

JAVA POD LUPOU

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 29/36

Komunikaèné spojenie medzi javovskou aplikácioua URL zabezpeèuje abstraktná trieda URLConnection.Konštruktor tejto triedy je chránený, nové objekty získa-me volaním metódy openConnection() nad objektomtypu URL. Trieda obsahuje mnostvo metód, z týchvýznamnejších vyberáme: connect() – fyzicky zrealizujepoadované spojenie (teda prepojí obe komunikujúcestrany), getContentLength(), getContentType(),getContentEncoding(), getExpiration(), getDate() a

getLastModified() – vracajú rovnako pomenované poliahlavièky, nachádzajúcej sa na zaèiatku odpovede vzdiale-ného poèítaèa (spomeòme si hoci na polia štandardnejhlavièky HTTP), ve¾mi dôleitá metóda   getContent() –vracia samotný dátový obsah URL, getInputStream()/getOutputStream() – vracajú prúdy na èítanie alebo zápisz/do spojenia, a mnoho ïalších.

 Java poskytuje dve inkarnácie triedy URLConnection –pre HTTP spojenia je to HttpURLConnection a pre spoje-nia k archívom JAR zase JarURLConnection. Obe triedy súabstraktné, take skutoèná implementácia spojení jezáleitosou konkrétneho JVM. V triedeHttpURLConnection nájdeme mnostvo statických finál-nych èlenov, reprezentujúcich stavové kódy protokoluHTTP a nieko¾ko špecifických metód: setFollow-

Redirects() – zapína èi vypína automatické presmerova-nie (pri vrátení kódu 3xx), setRequestMethod() – nasta-vuje prístupovú metódu (GET, POST a pod.),getResponseCode(), getResponseMessage() – vracajúnávratový kód, resp. návratovú správu HTTP protokolu,ako aj nieko¾ko ïalších, menej významných metód.

Druhá trieda JarURLConnection sa dostáva k slovu priprístupe k súborom JAR – URL má vtedy formát jar:http:/ /www.niekde.sk/ar chiv.jar!/ sk/niekde /foo/bar.c lass

(ako vidie, za výkrièníkom sa nachádza cesta ku kon-krétnej triede – poloke súboru JAR). Z metód triedy spo-menieme getEntryName() – vracia názov sprístupòova-nej poloky, getJarFile(), getJarEntry(), getManifest(),getAttributes() – vracajú objekty typu  JarFile,  JarEntry,Manifest, Attributes (pozri balík java.util.jar ).

Príklad, ako vypísa HTML obsah vybranej webovejstránky (obsah, pochopite¾ne, nie je nijako interpretova-ný):

URL url = new URL("http://www.pcrevue.sk/");URLConnection uc = url.openConnection();uc.connect();BufferedReader br =

new BufferedReader(new InputStreamReader(uc.getInputStream()));

 while (true){

String line = br.readLine();if (line == null) break;

System.out.println(line);}

Všimnite si, e sa vôbec nestaráme o to, akého typu jeobjekt uc v skutoènosti.

Okrem komunikácie so zadaným URL mono v Javevytvori spojenie priamo medzi dvoma soketmi (soket jekoncový komunikaèný bod, identifikovaný adresou IPa èíslom portu). Trieda Socket reprezentuje klientskysoket pre prúdovú komunikáciu pomocou TCP. Pri jejkonštrukcii môeme zada cie¾ovú adresu a port (soket sapotom automaticky spojí so svojím náprotivkom) a ajlokálnu adresu a port (to keï chceme „vysiela“ z kon-krétneho portu). Metódami getInetAddress(),getLocalAddress(), getPort() a getLocalPort() zistímevlastnosti soketu, pomocou getInputStream() agetOutputStream() získame prúdy na èítanie a zápis z/dosoketu. Metóda close() ukonèí komunikáciu a soket uza-vrie. Nieko¾ko ïalších metód slúi na nastavenie para-metrov komunikácie. Zaujímavé je, e samotnú komuni-káciu realizuje objekt typu SocketImpl (abstraktná trie-da). Pokia¾ si však nechceme napísa vlastnú implemen-

táciu soketov, nie je táto trieda zaujímavá.Ak programujeme serverovú èas aplikácie, pouijeme

triedu ServerSocket. Argumentom jej konštruktora jeèíslo portu, na ktorom bude soket poèúva.Najdôleitejšou metódou je  accept(), ktorej volanie jeblokujúce – metóda èaká, a sa na soket pripojí klient„zvonka“. V tom okamihu vracia objekt typu Socket,pomocou ktorého mono s klientom komunikova štan-dardným spôsobom. Z ïalších metód medzi tie zaujíma-

vejšie patrí getInetAddress(), getLocalPort() a close()s významom rovnakým ako v triede Socket.

Ako vyzerá kostra serverovej aplikácie, mono lepšiepochopi z nasledujúceho príkladu:

ServerSocket ss = new ServerSocket(12345); while (true){

Socket cs = ss.accept();BufferedReader br =

new BufferedReader(new InputStreamReader(cs.getInputStream()));

 while (true){

String ln = br.readLine();if (ln == null) break;

System.out.println(ln);}cs.close();

}

(Kompletnejšiu verziu nájde èitate¾ spolu s ostatnými prí-kladmi na webe PC REVUE.)

V príklade vytvoríme serverový soket ss, poèúvajúcina porte è. 12345. V nekoneènom cykle pomocou metódyaccept() získame klientsky soket cs, z ktorého èítameriadky textu a vypisujeme na konzolu. Na otestovanie jepotrebné pripoji sa k poèítaèu, na ktorom program beí,napríklad pomocou telnetu (ale na porte 12345!).Posielané riadky sa budú postupne objavova na konzole.Program sa ukonèí stlaèením Ctrl+C.

Na datagramový prenos pomocou protokolu UDP (bezspojenia, nezabezpeèený) slúi trieda DatagramSocket.Pri jej konštruovaní môeme zada èíslo lokálneho portusoketu. Pripojenie k zadanej vzdialenej adrese (pozor, nievytvorenie sieového spojenia ako pri TCP) má na staros-ti metóda connect(), odpojenie metóda disconnect(). Napríjem a odosielanie údajov slúia metódy send() a rece-ive(), soket uzavrieme volaním close(). Ostatné metódysú podobné ako v triede Socket, implementáciu soketovzabezpeèuje trieda DatagramSocketImpl.

Keïe v prípade UDP nejde o prúdový prenos, nepra-cujeme s prúdmi, ale s objektom triedy DatagramPacket(ten je ostatne argumentom oboch metód – send() ajreceive()). Pri jeho konštruovaní zadávame pole bajtov,ktoré bude fungova ako prijímací alebo vysielací buffer,

a pri odosielaných datagramoch aj cie¾ovú adresu.Pomocou metód triedy DatagramPacket môeme nasta-vova a zisti zdrojovú, resp. cie¾ovú adresu a port, dåkuúdajov a samotné údaje.

Na záver spomeòme ešte výnimky: Malformed-URLException (chyba v syntaxi URL), ProtocolException(chyba na úrovni prenosového protokolu), Socket-Exception s potomkami (chyba pri práci so soketmi),UnknownHostException (chyba pri preklade pomocouDNS) a UnknownServiceException (pokus o prácu s ne-známym MIME typom).

ia¾, na viac z balíka java.net nemáme miesto. Zvyšnétriedy slúia napríklad na implementáciu multicast soke-tov (MulticastSocket), zabezpeèenie prístupových práv(SocketPermission, NetPermission, Authenticator ),

prácu s URL a interpretáciu obsahu (ContentHandler ,URLStreamHandler ) èi konverziu medzi typom Stringa MIME typom  x-www-for m-urlencoded (URLEncoder ,URLDecoder ). Záujemca si viac informácií isto nájde pria-mo v dokumentácii.

15.èas : Bal ík java.awt

AWT je skratka názvu  Abstract Windowing Toolkit . Súbortried zdruených v balíku  java.awt a v jeho podbalíkoch je urèený na tvorbu pouívate¾ského rozhrania a prácus grafikou. Dnes sa skôr dáva prednos komponentomSwing , ktoré sú univerzálnejšie, flexibilnejšie a poskytujúväèšie monosti. Napriek tomu nie je AWT úplne odsúde-

ný na zánik; pre jednoduchšie aplikácie postaèí (a prácas ním je v urèitých oh¾adoch o nieèo jednoduchšia).Okrem toho Swing  stavia na základoch vybudovanýchpomocou AWT.

Vzh¾adom na rozsiahlos celého balíka nebude jehoopis taký vyèerpávajúci ako v predchádzajúcich èastiach.Nieko¾ko väèších príkladov nájde èitate¾ ako vdy nainternetových stránkach PC REVUE.

Hierarchia komponentov Jadrom balíka  java.awt  je hierarchia komponentovpouívate¾ského rozhrania (ïalej len UI). Pouíva sa tra-dièný okienkový systém, niektoré komponenty môuv sebe obsahova ïalšie komponenty. Interakcia po-uívate¾a s komponentmi sa transformuje na udalosti

(ako stlaèenie klávesu, kliknutie myši a podobne).Komponenty dokáu na výskyt udalostí vhodne reagova,štandardným spôsobom alebo na základe správania špe-cifikovaného programátorom.

Trieda ComponentKoreòom hierarchie je abstraktná trieda Component,predstavujúca univerzálny objekt, ktorý má nejakú gra-fickú reprezentáciu, môe by zobrazený na obrazovkea dokáe interagova s pouívate¾om. Komponenty UI súobyèajne implementované pomocou natívnych kompo-nentov hostite¾skej platformy, ale v prípade potrebymôe programátor odvodi vlastných potomkov triedyComponent a vytvori tak tzv. lightweight komponenty,ktoré nie sú implementované natívnymi objektmi – je

oèividné, e potom treba naprogramova úplne všetko –od zobrazovania komponentu v jeho rôznych stavoch podefinovanie spôsobu interakcie s pouívate¾om.

V triede Component nájdeme obrovské mnostvometód. Nie je moné ich tu všetky vymenova, tak sapozrieme aspoò na tie najdôleitejšie (zápis (get|set)*()reprezentuje dvojicu metód get*() a   set*() na získaniea nastavenie hodnoty nejakého atribútu): (get|set)Name() – názov komponentu, getParent() vracia ro-dièovský komponent, getToolkit() vracia objekt triedyToolkit (pozri ïalej), isVisible()/isEnabled() zisuje, èi jekomponent vidite¾ný a prístupný, setVisible()/setEnabled() nastavuje vidite¾nos a prístupnos kompo-nentu, (get|set)Foreground() a (get|set)Background() –farba popredia, resp. pozadia komponentu, (get|set)

Font() – font pouitý v komponente, (get|set)Location()– poloha komponentu, (get|set)Size() – rozmery kompo-nentu, getX()/getY() – súradnice ¾avého horného rohukomponentu, getWidth()/getHeight() – šírka/výška kom-ponentu, getPreferredSize()/getMinimumSize()/getMaximumSize() – predpokladaná (poadovaná), mini-málna a maximálna ve¾kos komponentu, getGraphics()vracia objekt typu Graphics (pozri ïalej),(get|set)Cursor() – typ kurzora priradený komponentu,paint() vykreslí komponent, update() obnoví obsah kom-ponentu (zmae pozadie a zavolá metódu paint()), repa-int() spôsobí, e sa èo najskôr zavolá metóda  update()(mono zada, ktorá èas komponentu sa má prekreslia za aký èas), contains() zisuje, èi komponent obsahujezadaný bod, getComponentAt() zisuje, èi samotný kom-ponent alebo niektorý z jeho podkomponentov obsahujezadaný bod.

Nasledujúca séria metód pripojí ku komponentu, resp.odoberie od neho špeciálny objekt, tzv. listener , ktorýbude dostáva správy o udalostiach týkajúcich sa kompo-nentu. Metódy majú tvar (add|remove)*Listener(), kde

PC REVUE 29

JAVA POD LUPOU

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 30/36

namiesto hviezdièky môe by niektoré zo slovComponent (udalosti týkajúce sa komponentu), Focus(získanie alebo strata fokusu), Hierarchy a Hierarchy-Bounds (zmena hierarchie komponentov), Key a Input-Method (udalosti klávesnice), Mouse a MouseMotion(udalosti myši) a PropertyChange (zmena fontu, farbypopredia alebo farby pozadia). Metóda getListeners()vracia pole všetkých listenerov pripojených ku kompo-nentu.

Zo zvyšných metód medzi významnejšie patria ešte:requestFocus() iada o presun vstupného fokusu na kom-ponent, transferFocus() presúva fokus na ïalší kompo-nent, hasFocus() zisuje, èi má komponent fokus,add()/remove() pridáva/odoberá kontextové (popup)menu ku komponentu, list() „vypíše“ obsah komponentudo zadaného výstupného prúdu (vhodné na ladenie).

Kontajnerové komponentyDôleitým potomkom triedy Component  je triedaContainer . Inštancie triedy Container  dokáu fungovaako kontajnery – môu v sebe obsahova iné komponen-ty. (Máme na mysli vizuálne „obsiahnutie“ – okno naprí-klad obsahuje ovládacie prvky, ako tlaèidlá, textové poliaa podobne.) Komponenty sú v kontajneri uloené v urèi-

tom poradí, ktoré urèuje ich prípadné vzájomné prekrý-vanie. Usporiadanie komponentov v kontajneri zabez-peèuje layout manager, èo je objekt implementujúci roz-hranie LayoutManager (viac o layoutoch pozri ïalej).

Z nových metód triedy Container  k významnejšímpatria: getComponent()/getComponents() sprístupòujevybraný komponent (alebo všetky vo forme po¾a),getInsets() vracia objekt Insets, definujúci ve¾kos okra- jov kontajnera, add()/remove()/removeAll() pridáva,resp. odstraòuje komponenty do/z kontajnera,(get|set)Layout() zisuje/nastavuje layout manager prekontajner, validate() spôsobí, e sa komponenty kontaj-nera znovu rozmiestnia pod¾a aktuálneho layoutu (vhod-né napríklad po pridaní nových komponentov),(add|remove)ContainerListener() pripája/odoberá kon-tajnerový listener, findComponentAt() je podobná metó-de getComponentAt(), ale na rozdiel od nej preh¾adávavšetky dcérske komponenty.

Trieda Container  nie je implementovaná natívnymkomponentom, take sa v praxi stretneme skôr s jejpotomkami. Najjednoduchším je Panel, komponentovýkontajner bez akejko¾vek pridanej funkènosti. TriedaPanel sa hodí napríklad v prípade, e chceme v jednomkontajneri poui rôzne layouty. Ïalší potomok,ScrollPane, predstavuje panel s pridanou monosourolovania obsahu pomocou posuvníkov. ScrollPane smieobsahova len jediný dcérsky komponent, ktorémuposkytuje schopnos rolovania. Z metód za zmienku stojílen dvojica (get|set)ScrollPosition() , pomocou ktorejmono pracova s aktuálnou pozíciou dcérskeho kompo-nentu v rámci panela.

Dôleitým kontajnerom je trieda Window, predstavu- júca okno bez okrajov a bez menu. Ak chceme vytvoriobjekt triedy Window, musíme zada jeho rodièovskéokno (iný objekt typu Window alebo niektorého z odvo-dených typov Frame a Dialog). Podstatné metódy triedyWindow: pack() zmení ve¾kos okna tak, aby sa doòpráve vošli všetky vnorené komponenty, show()/hide()zobrazuje/skrýva okno, dispose() okno zruší,toFront()/toBack() presúva okno do popredia/do pozadia,getOwner() vracia vlastníka okna, getOwnedWindows()vracia vlastnené okná, (add|remove)WindowListener()pridáva/odoberá „okenný“ listener.

Praktickejšími potomkami triedy Window sú dve u

spomínané triedy Frame a Dialog. Trieda Frame predsta-vuje okno najvyššej úrovne s titulkom a okrajom. Väèšinanových metód umoòuje èíta a meni atribúty okna:(get|set)Title() – titulok okna, (get|set)IconImage() –ikona okna, (get|set)MenuBar() – hlavné menu okna,(get|set)State() – stav okna (èi je minimalizované).Statická metóda getFrames() vracia pole všetkých objek-

tov typu Frame, ktoré práve beiaca aplikácia dosia¾ vytvorila.

Druhá trieda Dialog reprezentuje dialógové okná, kto-rým pri konštrukcii treba urèi vlastníka. Dialógové oknámôu by modálne (kým sú zobrazené, nemono praco-va s inými top-level oknami aplikácie) alebo nemodálne.Z metód spomenieme (is|set)Modal() na zistenie alebonastavenie modality dialógu a (is|set)Resizable() na zis-tenie alebo nastavenie schopnosti meni ve¾kos dialógu.

Špeciálnym potomkom triedy Dialog je trieda FileDialog,predstavujúca dialóg na výber názvu súboru. Táto triedaposkytuje metódy (get|set)Directory , (get|set)File() ,(get|set)FilenameFilter() na zistenie èi nastavenie názvua cesty vybraného súboru, ako aj metódy   (get|set)Mode()na špecifikovanie, èi je vybraný súbor urèený na èítaniealebo zápis.

Ovládacie prvkyZostávajúci potomkovia triedy Component predstavujúklasické ovládacie prvky. Triedu Label pouijeme na zob-razenie needitovate¾ného textu. Pri jeho konštrukciimôeme zada, èi má by zarovnaný na ¾avý okraj, nastred alebo na pravý okraj. S textom pracujeme pomocoumetód (get|set)Text(), so zarovnaním pomocou

(get|set)Alignment().Trieda Button reprezentuje tlaèidlo, ktoré obsahuje

volite¾ný text, a ktoré mono stlaèi pomocou myši aleboklávesnice. S textom na tlaèidle pracujeme pomocoumetód   (get|set)Label() a ohlas na stlaèenie tlaèidlazabezpeèí príslušný listener (môe ich by aj viac), ktorýpridávame a odoberáme metódami (add|remove)ActionListener().

Trieda Checkbox predstavuje dvojstavové zaškrtáva-cie pole s volite¾ným textom. Tento text sprístupòujedvojica metód (get|set)Label(), stav po¾a zase dvojicametód (get|set)State(). Zmenu stavu po¾a môe registro-va listener, ktorý pridávame a odoberáme metódami(add|remove)ItemListener(). Objekty Checkbox môuby zdruované do skupín, reprezentovaných objektmitriedy CheckboxGroup (pozor, nie je potomkom triedyComponent!) – vtedy sa z nich stávajú prepínaèe (radiobuttons). Pomocou metód  (get|set)SelectedCheckbox()máme prístup k aktuálne zvolenému prepínaèu.

Rozba¾ovací (drop-down) zoznam reazcových po-loiek reprezentuje trieda Choice. Poloky sa do zozna-mu pridávajú metódami add() a insert(), odoberajú sapomocou remove(). Poloku s daným indexom môemezíska metódou getItem(). Index aktuálne vybranejpoloky vracia metóda getSelectedIndex(), vybranúpoloku ako reazec získame pomocou getSelectedItem() .Metódou select() môeme nastavi, ktorá poloka budevybraná, a dvojica metód (add|remove)ItemListener()slúi na pridanie/odobranie listenerov.

Klasický (teda nerozba¾ovací) zoznam vytvorímepomocou triedy List. Pri konštrukcii zoznamu môemezada poèet zobrazených riadkov (implicitne 4), ako aj to,èi je moné vybra viac ako jednu poloku (multiselectlist). Metódy triedy List sú podobné metódam triedyChoice. Z nových metód spomeòme replaceItem(),pomocou ktorej môeme zmeni vybranú poloku,getSelectedIndexes() a getSelectedItems(), ktoré vracajúindexy vybraných poloiek alebo priamo poloky voforme po¾a (ináè to pri multiselect zoznamoch ani nejde),deselect() na zrušenie výberu zadanej poloky,isIndexSelected() na zistenie, èi je poloka s daným inde-xom vybraná.

Trieda Scrollbar  predstavuje vodorovný alebo zvislýposuvník (nemýli si s triedou ScrollPane, na ktorú sa

v zásade môeme pozera ako na kombináciu objektuPanel a dvoch objektov typu Scrollbar ). Pri konštrukciiposuvníka alebo neskôr pomocou samostatných metódmôeme zada orientáciu, povolený rozsah hodnôt, ktorébude ahadlo posuvníka reprezentova, a ve¾kos prírast-kov pri kliknutí na šípku alebo na plochu posuvníka.Metód je prive¾a na to, aby sme ich všetky vymenovali

(ide vdy o get/set dvojice), take za všetky spomeniemeiba metódu getValue(), ktorá vracia aktuálnu hodnotu,ktorú posuvník (resp. jeho ahadlo) reprezentuje.

Ïalšia trieda TextComponent  je spoloèným predkomkomponentov urèených na editáciu textu. S textom akocelkom mono pracova pomocou metód (get|set)Text(),metóda getSelectedText() vracia aktuálne vybranú(obyèajne inverzne zvýraznenú) èas textu. Ak chcemeprogramovo vyznaèi úsek textu, pouijeme metódu

select(). Volaním   setEditable() sa dá komponent„zamknú“, metódy (set|get)CaretPosition() nasta-vujú/zisujú polohu textového kurzora. K textovémukomponentu môeme pomocou (add|remove)TextListener() pripoji/odobra príslušný listener.

Od triedy TextComponent sú odvodené dve ïalšietriedy: TextField a TextArea. Prvá z nich predstavuje kla-sické jednoriadkové textové pole. Pri jeho konštrukciimôeme zada poèiatoèný obsah a šírku po¾a v znakoch.Z uitoèných metód pribudla predovšetkým dvojica(get|set)EchoChar(), umoòujúca nastavi/zisti znak,ktorý sa bude zobrazova namiesto jednotlivých písmentextu (typicky to býva hviezdièka pri textových poliach,do ktorých sa zadáva heslo). Druhá trieda, TextArea,reprezentuje viacriadkové textové editaèné pole s mo-

nosou automatického zobrazovania posuvníkov, ak jeobsah dlhší ako rozmery po¾a. Pri konštrukcii môemezada rozmery po¾a (v riadkoch a znakoch). Pomocoumetód insert() a append() môeme text do po¾a pridáva,metóda replaceRange() poskytuje monos nahradivybraný úsek textu iným reazcom.

Poslednou komponentovou triedou je Canvas. Tátotrieda slúi ako základ pre vlastné, pouívate¾sky kresle-né komponenty, ktoré na tento úèel musia predefinovametódu paint(). Pohybujeme v oblasti programovania ria-deného udalosami, nemôeme si preto do okna kresli,kedy sa nám zachce, ale iba vtedy, keï nám to systémdovolí. Filozofia je našastie ve¾mi jednoduchá: v okami-hu, keï treba komponent prekresli, zavolá sa jeho metó-da paint(). Ak ju nahradíme vlastnou verziou, máme pro-ces kreslenia „pod palcom“.

Usporiadanie komponentovAko sme u spomenuli, usporiadanie komponentovv rámci kontajnerov majú na starosti zvláštne objekty,ktoré implementujú rozhranie LayoutManager . Toto roz-hranie obsahuje nieko¾ko metód, ktoré sú volané kontaj-nerom (a pokia¾ nebudeme písa vlastný manaér, ne-musíme sa nimi zapodieva) a má jedného potomka, roz-hranie LayoutManager2, pridávajúce schopnos rozmiest-òova komponenty na základe zadaných obmedzení.

V balíku  java.awt nájdeme pä manaérov.Najjednoduchší je zrejme FlowLayout, ktorý umiestòujekomponenty do kontajnera v riadkoch z¾ava doprava.

Keï sa komponent na riadok nezmestí, „preteèie“ doïalšieho riadka. Pri zmene ve¾kosti kontajnera sa kompo-nenty prelievajú z riadka na riadok pod¾a aktuálnych roz-merov. Pri konštrukcii objektu FlowLayout môemezada spôsob zarovnania komponentov v rámci riadkaa ve¾kos medzery medzi komponentmi. Kontajnery trie-dy Panel majú implicitne nastavený manaér FlowLayout(zopakujme, e layout manager kontajnera sa nastavujepomocou metódy setLayout()).

Ïalší manaér, trieda GridLayout, usporiadava kom-ponenty do pravouhlej siete. Pri konštrukcii mono zadapoèet ståpcov a riadkov siete i rozstup komponentov.Kadý komponent zaberá jednu „bunku“ siete (nejde tedao umiestòovanie na zadanú pozíciu, ako je to benév iných prostrediach).

Trieda BorderLayout umiestòuje komponenty do jed-nej z piatich oblastí, pomenovaných príznaène sever, juh,západ, východ, stred. Opätovne mono zada ve¾kosmedzier medzi komponentmi.

Manaér triedy CardLayout zoradí všetky komponen-ty nad seba a zobrazí vdy len jeden z nich (vytvára tedaakoby balíèek kariet). To, ktorý komponent bude navr-

30 PC REVUE

JAVA POD LUPOU

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 31/36

chu, nastavíme pomocou metód first(), last(), next(), pre- vious() a show().

Najzloitejším a súèasne najmocnejším manaérom jeGridBagLayout. Nanešastie nemáme miesto na jehopodrobnejší opis, v skratke platí, e pre kadý kompo-nent môeme (ba musíme) zada mnostvo obmedzení(vo forme objektu triedy GridBagConstraints ). Tietoobmedzenia opisujú, kde sa komponent bude nachádza(v rámci pomyselnej mrieky – podobne ako pri

GridLayout), èi bude zabera viacero buniek mrieky, èisa zväèší tak, aby zaplnil celú oblas, ktorú má k dispozí-cii, ve¾kos medzier okolo komponentu, dokonca môemestanovi, ktoré komponenty budú meni svoje rozmerypri zmene ve¾kosti kontajnera a ktoré zostanú nemenné.

Ak potrebujeme v rámci jedného kontajnera pouiviacero layoutov, musíme skupiny komponentov umiest-ni na samostatné panely s potrebnými layout mana-érmi a tieto panely vloi do kontajnera.

Práca s grafikouAk chceme v programe zobrazova kreslený výstup(napríklad v prípade vlastných komponentov), celkomisto prídeme do styku s triedou Graphics. Táto abstrakt-ná trieda predstavuje grafický kontext (podobne akonapr. vo Windows), v rámci ktorého existuje nieko¾kocharakteristík: komponent, do ktorého sa bude kresli,poloha a farba pera, font pouitý pri kreslení textua podobne. Inštanciu typu Graphics pre poadovanýkomponent získame volaním metódy getGraphics().

V triede Graphics nájdeme mnoho metód na zisova-nie a nastavovanie uvedených charakteristík, nastavenieorezávacieho obdånika (clipping rectangle – oblas,mimo ktorej sa prípadný grafický výstup bude ignoro-va), kreslenie èiar, plných aj prázdnych obdånikov,elíps, oblúkov, polygónov, textových reazcov, obrázkova podobne. Trieda Graphics2D, ktorá je potomkom triedyGraphics, tieto monosti ešte rozširuje.

Pomocné triedyZ mnostva ïalších tried spomenieme Point na reprezen-táciu dvojrozmerných bodov s metódami na absolútnu(move()) aj relatívnu (translate()) zmenu súradníc, trieduColor na reprezentáciu farieb v modeli RGBA (teda s pod-porou prieh¾adnosti), ktorá obsahuje aj preddefinovanékonštanty pre nieko¾ko najbenejších farieb, jej potomkaSystemColor na reprezentáciu systémových farieb, ïalejtriedu Cursor na prácu s preddefinovanými typmi kurzo-rov, pomerne komplexnú triedu Font na reprezentáciufontov, ktoré sú v systéme k dispozícii, spolu s triedouFontMetrics, ktorá opisuje rozmerové vlastnosti fontov,triedu Insets, ktorá sa pouíva na opis ve¾kosti okrajovkontajnera alebo komponentov umiestòovaných pomo-cou manaéra GridBagLayout, a triedy Rectangle

a Polygon, predstavujúce obdåniky a polygóny, s metó-dami na rôzne geometrické operácie (zjednotenie, prie-nik, test polohy bodu voèi objektu a pod).

16.èas: Balík java.awt (dokonèenie)

V predchádzajúcom pokraèovaní sme zabudli spomenúešte dve významnejšie pomocné triedy. Prvá z nich,Dimension, predstavuje zapuzdrenie šírky a výšky kom-ponentu do jedného objektu. Druhá s názvom Toolkit jepodstatne komplexnejšia a dá sa poveda, e reprezentu- je implementáciu AWT. Nájdeme v nej mnostvo metód

na vytváranie natívnych komponentov, ale aj uitoènémetódy getScreenSize() a getScreenResolution() na zis-tenie parametrov obrazovky, getImage(), createImage(),prepareImage() a checkImage() na prácu s obrázkami,metódu beep(), ktorá generuje systémové „pípnutie“a mnoho ïalších.

Menu komponentyNa prácu s menu slúi skupina tried so spoloèným pred-kom, abstraktnou triedou MenuComponent. Kadý menukomponent má svoj názov, ktorý môeme zisti a nasta-vi dvojicou metód (get|set)Name(). Metóda getParent()vracia rodièovský kontajner, v ktorom je zadaný kompo-nent obsiahnutý, metódy (get|set)Font() slúia na ziste-nie a nastavenie fontu pouitého v menu komponente.

Obyèajné, ïalej nerozbalite¾né poloky menu predsta-

vuje trieda MenuItem. Pri konštrukcii poloky zadávameako parameter textový reazec, ktorý sa zobrazí v menu.Tento reazec môeme neskôr zisova a nastavovametódami (get|set)Label(). Poloky môu by nastavenéako neaktívne (a obyèajne zobrazené svetlou, nevýraz-nou farbou) volaním metódy setEnabled(). Pomocoumetód (get|set)ActionListener() môeme k poloke pri-poji príslušný listener.

Špeciálnym prípadom poloky menu je triedaCheckboxMenuItem (odvodená od MenuItem). Tá obsa-huje navyše binárny stav, indikovaný zaškrtávacou znaè-kou. Stav môeme zisova a nastavova pomocou metód(get|set)State().

Základným typom menu kontajnera je trieda Menu,ktorá reprezentuje vertikálne menu. Jednotlivé polokymenu musia by typu MenuItem, a keïe samotná triedaMenu  je potomkom triedy MenuItem, nie je problémvytvori hierarchickú štruktúru menu jednoduchým skla-daním. Objekt triedy Menu má svoj názov a môe pred-stavova oddelite¾né (tear-off) menu. Túto skutoènosindikuje metóda isTearOff(). Z ïalších metódgetItemCount() vracia poèet poloiek v kontajneri,getItem() sprístupòuje jednotlivé poloky, add(), insert()a remove() slúia na pridávanie alebo odoberaniepoloiek. Špeciálnym typom poloiek sú odde¾ovaciepruhy, ktoré pridávame pomocou metód addSeparator()a insertSeparator().

Vodorovný pruh s polokami menu implementuje trie-da MenuBar . Jednotlivé poloky musia by typuMenuItem (plus všetkých jeho potomkov). Objekt triedyMenuBar sa pripája ku komponentom typu Frame pomo-cou metódy Frame.setMenuBar(). Na pridávanie a odobe-ranie poloiek menu máme k dispozícii metódy add()a   remove(), poèet poloiek v menu zistíme volanímgetMenuCount().

V AWT mono vytvára aj kontextové menu, ktorénemusia by súèasou vodorovného menu okna, ale môuby zobrazené na zadanej pozícii. Takéto menu sú objekt-mi triedy PopupMenu, ktorá je odvodená od Menu; zob-razenie menu má na starosti metóda show().

Ukáme si ešte krátky príklad, ako zostroji základnémenu s dvoma podmenu  File a  Help a s nieko¾kýmipolokami (predpokladáme, e uvedený kód je súèasoukonštruktora okna – kompletný príklad mono tradiène

nájs na webe):Menu mnFile = new Menu("File");mnFile.add(new MenuItem("New"));mnFile.add(new MenuItem("Open..."));mnFile.add(new MenuItem("Save"));mnFile.add(new MenuItem("Save as..."));mnFile.addSeparator();mnFile.add(new MenuItem("Exit"));

Menu mnHelp = new Menu("Help");mnHelp.add(new MenuItem("About..."));

MenuBar mb = new MenuBar();mb.add(mnFile);mb.add(mnHelp);

setMenuBar(mb);

Rozhrania java.awtZ rozhraní balíka java.awt za zmienku stoja nasledujúce:Adjustable reprezentuje objekty, ktoré umoòujú zmenuèíselnej hodnoty v stanovenom rozsahu. Z balíka java.awt je takým objektom trieda Scrollbar . Rozhranie

ItemSelectable predstavuje objekty obsahujúce zoznampoloiek, ktoré mono nejakým spôsobom „vybra“ – akonapríklad triedy List, Checkbox èi Choice.

Rozhranie MenuContainer  implementujú všetky trie-dy, ktoré fungujú ako menu kontajnery. Okrem Menua MenuBar  je to tie trieda Frame a na úèely prípadnéhorozširovania aj trieda Component.

Všetky triedy, ktoré dokáu rozmiestòova komponen-ty v kontajneroch, implementujú rozhranie Layout-

Manager . Potomkom tohto rozhrania je Layout-Manager2, opisujúci triedy, ktoré vedia rozmiestòovakomponenty aj na základe zadaných obmedzení.

Chyby a výnimkyVánu, neopravite¾nú chybu AWT indikuje objekt triedyAWTError , odvodenej od triedy Error . Tá, ako vieme,predstavuje chyby, pri ktorých sa nepredpokladá obno-venie normálnej èinnosti programu a nie je nevyhnutnéich zachytáva. Bené výnimky AWT sú naproti tomu sig-nalizované triedou AWTException. Okrem nej nájdemev balíku  java.awt ešte výnimky FontFormatException(chyba vo formáte súboru s definíciou písma) aIllegalComponentStateException (indikuje neplatný stavkomponentu).

Triedy udalostíÏalej sa budeme venova podbalíku  java.awt.event,ktorý obsahuje triedy a rozhrania urèené na obsluhu uda-lostí GUI. Spoloèným predkom pre triedy udalostí v AWT je trieda AWTEvent (patriaca však do balíka  java.awt).Inštancie tejto triedy, resp. jej potomkov, nevytváraprogramátor, ale samotný systém ako reakciu na výskytrôznych udalostí. Kadý typ udalosti je identifikovanýcelým èíslom, uloeným v chránenom èlene id. Jeho hod-notu zistíme pomocou metódy getID(). Ve¾mi èasto jenevyhnutné urèi konkrétny typ udalosti práve na zákla-de jej identifikaèného èísla.

„Akèné“ udalosti, ako napríklad kliknutie na objektButton, reprezentuje trieda ActionEvent. Pomocou metó-dy getActionCommand() môeme získa príkazovýreazec, asociovaný k akcii (rôzne tlaèidlá budú maobyèajne priradené rôzne reazce, pod¾a èoho môeme jednoducho identifikova, ktoré tlaèidlo bolo stlaèené);metóda getModifiers() vracia stav modifikaèných kláve-sov (Shift a pod.) v okamihu výskytu udalosti.

Trieda AdjustmentEvent predstavuje udalosti genero-vané triedami, ktoré implementujú rozhranieAdjustable, ako napríklad trieda Scrollbar . Pomocoumetódy getAdjustable() získame objekt, ktorý udalosspôsobil, getValue() vracia aktuálnu „hodnotu“ objektu(pri posuvníku je to poloha jazdca) a getAdjustment-Type() pouijeme na blišie urèenie typu udalosti.

Ïalšia trieda ComponentEvent zastupuje udalosti, ako

posun, zmenu ve¾kosti a vidite¾nosti komponentu a po-dobne. Tieto udalosti sú urèené len na informaèné úèely– systém sa postará o zodpovedajúce prekreslenie kom-ponentov sám.

Trieda ComponentEvent má nieko¾ko potomkov.Prvým z nich je trieda ContainerEvent, ktorá predstavu- je udalosti týkajúce sa kontajnerov (opä je urèená len nainformaèné úèely). FocusEvent reprezentuje získaniea stratu fokusu (ak má komponent fokus, znamená to, edoò budú smerované všetky vstupy z klávesnice; fokus saobyèajne znázoròuje vizuálne – ako bodkovaný obdånikèi silnejšie orámovanie).

Ïalší potomok InputEvent slúi ako spoloèný predokpre udalosti vstupu z klávesnice alebo myši. Pomocounieko¾kých metód môeme zisti stav modifikaèných klá-

vesov v okamihu výskytu udalosti. Udalosti klávesniceblišie špecifikuje odvodená trieda KeyEvent. Tieto uda-losti sú troch typov: stlaèenie klávesu, uvo¾nenie klávesua „vstup znaku“. Tretí typ udalosti býva dôsledkom výs-kytu prvých dvoch typov, v rôznych kombináciách (naprí-klad udalosti „vstup znaku A“ predchádzajú udalosti„stlaèenie Shift“, „stlaèenie a“, „uvo¾nenie a“ a „uvo¾-

PC REVUE 31

JAVA POD LUPOU

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 32/36

nenie Shift“). Príslušný znak a jeho kód získame volanímmetód getKeyChar() a getKeyCode(), slovný ekvivalentkódu znaku (ako napríklad „F1“) volaním metódygetKeyText(). Ïalšie metódy setKeyChar(), setKeyCode()a setModifiers() umoòujú zmeni kód znaku, ako kebybol stlaèený úplne iný kláves.

Udalosti myši, ako jej pohyb, prechod nad komponen-tom, stlaèenie a uvo¾nenie tlaèidiel, sú reprezentovanétriedou MouseEvent. Polohu myši zistíme pomocou

metód   getX() a   getY(), poèet kliknutí vracia metódagetClickCount() (jednoduché i dvojité kliknutie majú rov-naký identifikátor MOUSE_CLICKED, líšia sa v návratovejhodnote tejto metódy). Metóda isPopupTrigger() indiku- je, èi daná udalos slúi ako povel na zobrazenie kontex-tového menu pre danú platformu.

Trieda PaintEvent existuje v súvislosti s prekres¾ova-ním komponentov, pouíva ju však systém, nie progra-mátor. Poslednou komponentovou udalosou je triedaWindowEvent, indikujúca zmeny stavu okna (otvorenie,zavretie, maximalizáciu, minimalizáciu a pod.).

Udalosti súvisiace so zmenou hierarchie komponentovreprezentuje trieda HierarchyEvent, urèená opätovnelen na informaèné úèely. Udalosti oznaèenia a odznaèe-nia poloky v objekte typu ItemSelectable (takým je

napríklad trieda List) reprezentuje trieda ItemEvent.Príslušnú poloku získame volaním metódy getItem().Poslednou udalostnou triedou je TextEvent, ktorá indi-kuje zmenu textového obsahu v komponente.

Zachytávanie udalostíAko sme hovorili minule, jednotlivé komponenty AWTgenerujú rôzne mnoiny udalostí a iným objektomposkytujú monos reagova na výskyt týchto udalostí.Objekt, ktorý sa chce dozvedie o kadom výskyte neja-kého typu udalosti, pripojí k príslušnému komponentutzv. listener. Sú v zásade dva spôsoby, ako vytvori liste-ner: implementáciou príslušného „poèúvacieho“ rozhra-nia alebo odvodením od niektorej adaptérovej triedy.

„Poèúvacích“ rozhraní je spolu pätnás a všetky súodvodené od rozhrania EventListener  (neobsahuje iad-ne metódy, slúi len ako spoloèný predok). Nebudeme ichtu všetky menova, v zásade majú názvy korelujúces metódami typu (add|remove)*Listener()  jednotlivýchkomponentov. Jeden príklad za všetky: rozhranieActionListener . Toto rozhranie musia implementovavšetky listenery, ktoré majú zachytáva „akèné“ udalosti,ako napríklad kliknutie na tlaèidlo. Rozhranie tvorí jedi-ná metóda actionPerformed(), ktorá je volaná v okamihuvýskytu udalosti. Parametrom metódy actionPerformed() je objekt typu ActionEvent.

Treba ma na pamäti, e metóda actionPerformed() jesúèasou listenera a volá ju komponent, na ktorom k uda-losti došlo. Vo všeobecnosti si kadý komponent udrujezoznam všetkých zaregistrovaných listenerov a pri výs-kyte niektorej udalosti ich všetkých informuje zavolanímich príslušnej metódy.

Podobne vyzerajú aj ostatné „poèúvacie“ rozhrania,môu však obsahova aj viac ako jednu metódu, na indi-káciu rôznych podtypov udalostí (napríkladWindowListener  obsahuje sedem metód, zodpovedajú-cich siedmim podtypom udalosti WindowEvent). Urèitounevýhodou tohto spôsobu zachytávania udalostí môeby nutnos implementova všetky metódy príslušnéhorozhrania, aj keï máme záujem iba o jeden podtyp uda-losti. Malý príklad, ako pripoji k tlaèidlu akèný listener:

import java.awt.*;import java.awt.event.*;

...

Button b = new Button("OK"); b.addActionListener(new ButtonWatcher());

...

class ButtonWatcher implements ActionListener{ void actionPerformed(ActionEvent e){ // ošetrenie udalosti

}}

(Dva riadky kódu, na ktorých sa vytvára nový objekt typuButton a pripája sa k nemu listener, budú, pochopite¾ne,

súèasou nejakej metódy).Druhým spôsobom zachytávania udalostí je pouitie

niektorej z adaptérových tried. Ide o osem abstraktnýchtried, ktoré implementujú vybrané poèúvacie rozhrania.Metódy týchto tried sú implicitne prázdne. Ak od niekto-rej z tried odvodíme vlastný adaptér, postaèí reimple-mentova len tie metódy, o ktoré máme záujem (na roz-diel od poèúvacích rozhraní, kde sme povinní implemen-tova všetky metódy). Názvy adaptérových tried súpodobné názvom poèúvacích rozhraní, len namiestoslova Listener  je Adapter . Adaptérové triedy existujú lenpre rozhrania s viac ako jednou metódou.

Príklad pouitia triedy WindowAdapter :

 // nech f je inštanciou Frame

f.addWindowListener(new WindowWatcher());

...

class WindowWatcher extends WindowAdapter{ void windowClosing(WindowEvent e){ // reakcia na zavretie okna

}}

Treba ma na pamäti, e v praxi sa namiesto samostat-ných tried (ako sú ButtonWatcher  a WindowWatcher v našich príkladoch) èastejšie pouívajú triedy vnorenéalebo dokonca anonymné, take sa stretneme napríkladso zápisom:

f.addWindowListener(new WindowAdapter{ void windowClosing(WindowEvent e){ // reakcia na zavretie okna

}});

K anonymným triedam sa však dostaneme a neskôr.

Práca s obrázkamiÏalší podbalík  java.awt.image poskytuje triedy urèenéna vytváranie a úpravu obrázkov. Ako abstraktná repre-zentácia grafického obrázka slúi trieda Image (ktorápatrí do  java.awt ). Z dôleitých metód spomeòme

getWidth() a getHeight() na zistenie rozmerov obrázkaa getSource() na získanie objektu, ktorý má na starostivygenerovanie jednotlivých pixelov obrázka.

Na zaèiatku èlánku sme spomenuli triedu Toolkit,ktorá poskytuje nieko¾ko metód na vytvorenie a prácus obrázkami. V balíku java.awt.image sa nachádzajú trie-dy urèené pre komplexnejšie operácie. Práca s obrázkami je postavená na prúdovom modeli, ktorý zahàòa „produ-centa“ obrázka (implementuje rozhranie Image-Producer ), volite¾né filtre a „spotrebite¾a“ obrázka(implementuje rozhranie ImageConsumer ).

Základom obrázkových filtrov je trieda ImageFilter ,ktorá sa sama osebe javí ako spotrebite¾ obrázka. Tátotrieda predstavuje prázdny filter a slúi len ako bázováimplementácia. Praktickejšia je trieda CropImageFilter ,

ktorá dokáe pôvodný obrázok oreza na poadovanúve¾kos. Na jednoduchú zmenu rozmerov obrázka monopoui triedu ReplicateScaleFilter , ktorá pouíva najjed-noduchší moný algoritmus: opakuje riadky (pri zväèšo-vaní obrázka) alebo ich vynecháva (pri zmenšovaní).O nieèo lepšie výsledky dáva trieda AreaAveraging-

ScaleFilter , ktorá pri zmene rozmerov poèíta priemernéhodnoty pixelov. Najzaujímavejšia je však abstraktnátrieda RGBImageFilter , ktorá umoòuje filtrova obrázkyna základe zloiek RGB jednotlivých pixelov. Vzh¾adomna jej abstraktnos je jasné, e konkrétny filter trebanaprogramova reimplementáciou príslušných metód.

Na prepojenie producenta obrázka a niektorého z fil-trov pouijeme triedu FilteredImageSource. Tá sa samatvári ako producent, take v prípade nutnosti poui via-

cero filtrov staèí triedy vhodne zreazi rovnakým spôso-bom ako pri filtroch údajových prúdov.

Ostatné triedy spomeòme len struène: ColorModel jeabstraktná trieda na reprezentáciu farebných modelov. Jej konkrétne implementácie tvoria triedyComponentColorModel (zlokový model, jednotlivéfarebné zloky sú samostatnými údajmi),IndexColorModel (paletový systém, jednotlivé farby súindexmi do zadanej farebnej palety) a DirectColorModel,ktorá je odvodená cez medzipotomka PackedColorModel(opä zlokový model, jednotlivé zloky sú však skombi-nované do jedného údaja – napríklad model RGB565 v 16-bitových farebných reimoch).

Na reprezentáciu pixelového rastra slúi trieda Raster .Nad rastrami mono vykonáva rôzne operácie, ako afin-

né transformácie, konvolúcie a podobne. Údaje rastra súuloené v objekte typu DataBuffer .

Ïalšie podbalíkyV balíku java.awt mono nájs nieko¾ko ïalších podbalí-kov, ale s oh¾adom na rozsah èlánku sa im nebudemepodrobnejšie venova. Take len informatívne: balík java.awt.color obsahuje triedy na prácu s farebnými pro-filmi ICC. Balík  java.awt.datatransfer  poskytuje rozhra-nia a triedy na výmenu dát medzi aplikáciami (pomocouschránky – clipboardu). V balíku  java.awt.dnd sa nachá-dzajú triedy potrebné na implementáciu mechanizmudrag-and-drop. Ïalší balík java.awt.font v súlade so svo- jím názvom poskytuje triedy a rozhrania na prácu s pís-mami a ich opisnými súbormi (fontami). Balík java.awt.geom obsahuje mnostvo tried na prácu s dvoj-rozmernou grafikou. Balíky  java.awt.im a java.awt.im.spi umoòujú zápis netradièných znakov(typicky japonských, èínskych èi kórejských) pomocoutzv. vstupných metód. No a koneène v poslednom balíku java.awt.print nájdeme rozhrania a triedy na prácu stlaèiaròou.

Pri grafike zostaneme Java 2 obsahuje okrem AWT ešte jeden grafický rámecs poetickým názvom Swing. Ten je o nieèo bohatší a pri-spôsobite¾nejší. Viac si o òom povieme v budúcompokraèovaní.

17.èas : Thready a synchronizácia

Napriek s¾ubu v závere predošlej èasti sa balíku Swing aniïalším balíkom v tomto seriáli nebudeme venova. Prizloitejších témach toti vôbec nie je jednoduché efektív-ne zhrnú obrovské mnostvo informácií do jednej èidvoch èastí seriálu. Ak sa to podarí, výsledok pripomínaskôr referenènú príruèku a o tom seriál predsa nie je.Èitate¾ chtivý podrobnejších informácií preto budemusie h¾ada aj inde, najlepšie na internete.

MultithreadingSotva by sa dnes uivila programovacia platforma, ktoráby neumoòovala paralelné vykonávanie úloh. Pod¾aúrovne, na ktorej paralelizmus pozorujeme, môemehovori o multitaskingu alebo o multithreadingu. Prvýpojem oznaèuje schopnos súèasného behu viacerýchprocesov. Pod procesom si predstavme samostatne vyko-návanú exekuènú jednotku, ktorá má pridelený adresovýpriestor, disponuje vnútorným stavom a môe vlastni

32 PC REVUE

JAVA POD LUPOU

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 33/36

prostriedky OS. Skrátka, proces je „beiaci program“. Jeden binárny program môe bea súèasne vo viacerýchkópiách – kadá kópia je potom samostatným procesom.Multitasking sa dnes povauje za samozrejmos.

Pri multithreadingu rozdelíme jeden proces nanieko¾ko menších podprocesov, tzv. threadov. Názovpochádza z angliètiny, kde znamená „vlákno“. O threa-doch preto niekedy hovoríme ako o „exekuèných vlák-nach“. Thready medzi sebou zdie¾ajú adresový priestor,

môu však obsahova vlastné, privátne údaje. Dôvodom,preèo sa uchy¾ujeme k rozdrobeniu aplikácie na thready, je obyèajne snaha o zlepšenie pouívate¾ského ohlasu.V takom textovom editore sa jeden thread môe starao editáciu textu, ïalší o obnovu obrazovky, kontrolu pra-vopisu èi tlaè na pozadí. Keby toto všetko mal robi jedenthread, nebolo by moné pri tlaèení upravova text, prie-bene kontrolova pravopis a podobne. Existujú však ajtypy úloh, pri ktorých je výhodné poui thready z inéhodôvodu – napríklad na zjednodušenie algoritmu aleboimplementáciu zloitejšieho správania.

Ak máme dosiahnu paralelný beh viacerých procesovèi threadov na jednoprocesorovom systéme, musíme sauchýli k nejakému triku. Rýchlym prepínaním medzi jed-notlivými threadmi môeme vytvori ilúziu súèasnéhobehu viacerých úloh. V operaènom systéme zvyèajneexistuje samostatný modul, plánovaè (scheduler), ktorýsa stará o pride¾ovanie procesora jednotlivým threadomna základe vhodnej stratégie. Ak je plánovaè schopný pouplynutí vopred stanoveného èasového kvanta threadpozastavi a spusti iný, hovoríme o preemptívnom pláno-

vaní . (V ére šestnásbitových Windows, ktoré neposkyto-vali preemptívny multitasking, sa musel kadý beiaciproces explicitne a dobrovo¾ne zriec tohto svojho výsad-ného postavenia. Ak sa stalo, e sa program zasekol,spolu s ním išiel pod kytièky aj operaèný systém.)

Niektoré thready sú pre beh systému dôleitejšie. Abysa zabezpeèila plynulos ohlasu, majú thready priradenúceloèíselnú hodnotu priority. Plánovaè threadov preferujepri pride¾ovaní procesora thready s vyššou prioritou.Thready sa môu nachádza v rôznych stavoch, naj-hrubšie rozdelenie je na thready beiace (môe ich by ajviac ako jeden, napríklad na multiprocesorových systé-moch), thready pripravené na naplánovanie a thready„spiace“, ktoré èakajú na výskyt nejakej udalosti. Väèšinathreadov je poèas svojho ivota v tomto treom stave,pretoe èaká na vstup z klávesnice, na pohyb myši, navykreslenie obrázka, na dodanie údajov z disku a podob-ne. Len thready, ktoré intenzívne poèítajú, dokáu vyuisvoje èasové kvantum naplno.

Thread môe zmeni svoj stav aj inak ako vypršanímprideleného èasu – môe sa dobrovo¾ne zriec procesoraalebo môe vyjadri svoju potrebu èaka na splnenienejakej podmienky. Spiaci thread môe by zobudený

systémom alebo iným threadom, ktorý sa postaral o spl-nenie podmienky.

Thready a Java Java poskytuje dva spôsoby, ako vytvori thread. Prvým je odvodenie vlastnej podtriedy systémovej triedy java.lang.Thread. Jadrom threadu je metóda run() (treba ju, pochopite¾ne, predefinova), ktorá sa zaène vykonávapo spustení threadu. To dosiahneme zavolaním metódystart(). Thread beí, kým je v metóde run() èo robi. Lenèo sa v metóde vyskytne príkaz return èi nezachytenávýnimka a aj keï tok riadenia dospeje ku koncovejzátvorke, thread konèí a systém ho po èase zlikviduje.Ukáka vytvorenia a spustenia nového threadu:

class MyThread extends Thread{ // ...

}

MyThread mt = new MyThread();mt.start();

V príklade vytvárame objekt MyThread, ktorý sme odvo-dili od triedy Thread, a voláme jeho metódu start().

Druhý spôsob spoèíva v implementácii rozhraniaRunnable, ktoré obsahuje metódu run(). Objekt imple-mentujúci toto rozhranie potom môeme zada ako argu-ment konštruktora na vytvorenie objektu typu Thread.Pri tomto spôsobe sa po zavolaní metódy start() zaènevykonáva metóda run() objektu Runnable. Ukáka:

class MyThread implements Runnable{ // ...

}

MyThread mt = new MyThread();Thread tt = new Thread(mt); tt.start();

Ako vidno, tentoraz vytvárame dva objekty; jeden typuMyThread (to je ten, ktorý v metóde run() obsahuje kódnového threadu) a druhý typu Thread – ten funguje ako„obálka“ prvého objektu.

Pri vytváraní nového threadu môeme volite¾ne zada jeho meno; to sa môe hodi napríklad pri ladení projek-tu. Okrem toho môeme threadu prideli skupinu, do kto-

rej bude patri (pozri ïalej).Trieda Thread poskytuje nieko¾ko ve¾mi potrebnýchmetód. Pomocou metódy  yield() sa napríklad threadmôe vzda procesora. Zavolaním metódy sleep() threadna stanovený èas „zaspí“. Násilne preruši thread monometódou   interrupt(). Pomocou metódy   join() môemeprikáza aktuálnemu threadu, aby èakal na skonèenieiného threadu. Metóda isAlive() indikuje, èi daný threadije, t. j. èi bol spustený a dosia¾ beí. Názov a priorituthreadu zisujeme a nastavujeme dvojicami(get|set)Name() a (get|set)Priority().

 Javovský program sa konèí buï explicitným volanímSystem.exit(), alebo v okamihu, keï svoj beh skonèiavšetky thready. Pomocou metódy setDaemon() môemevybrané thready premeni na „démonov“ (a naopak).

Systém pri rozhodovaní, èi ukonèi program, na „démo-nické“ thready neberie oh¾ad. Metóda run() týchto threa-dov obyèajne obsahuje nekoneènú sluèku. Na zistenie, èi je vybraný thread démonom, pouijeme metóduisDaemon().

Skupiny threadovThready mono zluèova do skupín, ktoré tvoria stromo-vú štruktúru. Kadá skupina okrem poèiatoènej má pri-delenú rodièovskú skupinu. Pri vytvorení nového threadumono urèi, do ktorej skupiny bude thread zaradený.

Na reprezentáciu skupiny threadov je urèená triedaThreadGroup. Pri vytvorení jej mono prideli menoa rodièovskú skupinu. Ak rodièovskú skupinu nezadáme,stane sa òou automaticky skupina, do ktorej patrí aktuál-

ny thread. Pomocou metódy setMaxPriority() nastavuje-me maximálnu hodnotu priority, akú môu ma threadypatriace do skupiny. Z ïalších metód vyberámesetDaemon() na transformáciu všetkých threadov v sku-pine na démonov a naopak, interrupt() na prerušenievšetkých threadov v skupine, getName(), getParent(),getMaxPriority(), isDaemon(), isDestroyed() na zistenieatribútov skupiny èi  activeCount()/activeGroupCount()na zistenie poètu aktívnych threadov a aktívnych skupínpatriacich do zadanej skupiny.

V súvislosti s threadmi spomeòme ešte trieduThreadLocal. Táto trieda predstavuje zvláštny druhobjektov, líšiacich sa od bených premenných v tom, ekadý thread, ktorý s nimi pracuje, má k dispozícii vlast-nú, nezávisle inicializovanú kópiu. Objekty ThreadLocal

zvyèajne bývajú privátnymi statickými zlokami tried,ktoré s threadmi nejakým spôsobom súvisia.

Na èítanie a zápis hodnoty premenných typuThreadLocal pouijeme metódy get() a set(), ktoré pra-cujú s typom Object, take uloená hodnota môe byv podstate ¾ubovo¾ná. Poèiatoèná hodnota premenných je

null; ak potrebujeme poui inú inicializaènú hodnotu,musíme si odvodi vlastnú triedu a predefinova chráne-nú metódu initialValue().

SynchronizáciaNevyhnutným dôsledkom zavedenia multitaskingua multithreadingu je celkom nová trieda problémov,ktoré v jednopouívate¾ských a jednoúlohových prostre-diach prakticky neexistovali. Zoberme si ako príklad dva

thready, ktoré pracujú s rovnakými údajmi. V prípade, ekadý thread èíta a zapisuje údaje bez oh¾adu na tendruhý, ¾ahko môe dôjs k narušeniu integrity údajov.Majme nasledujúci kód:

 void run(){

for (int i = 0; i < 10; i++)x = x + 1;

}

Nech oba thready vykonávajú tento kód, ktorého úèelom je desakrát inkrementova premennú x, ktorá je prístup-ná obom threadom (napríklad je statickým èlenom tejtriedy, do ktorej patrí metóda run()). Predpokladajme, epoèiatoèná hodnota x je rovná nule. Ak najprv spustíme

 jeden thread a po jeho skonèení druhý, dostaneme výsle-dok 20. Nechajme teraz oba thready bea naraz. V závis-losti od okolností bude lea koneèný výsledok niekdev rozsahu od 10 po 20. Ako je to moné?

 Jadrom problému je riadok x = x + 1 (zámerne nie jepouitý operátor ++). Pri vyhodnocovaní tohto výrazuthread naèíta obsah premennej x do doèasnej pamäte(registra), zvýši ho v nej o jednotku a uloí naspä dohlavnej pamäte. Toto vyhodnotenie však nie je atomické(nedelite¾né) a v prípade, e threadu vyprší èasové kvan-tum niekde „uprostred“, v premennej x zatia¾ zostanestará hodnota. Druhý thread si odteraz s premennoumôe robi, èo chce, jeho úpravy budú onedlho zabudnu-té; len èo sa toti k slovu opä dostane prvý thread, doko-nèí vyhodnotenie výrazu a prepíše momentálnu hodnotux v hlavnej pamäti hodnotou, ktorá odpoèívala v pomoc-nom registri.

 Poznámka: Je pochopite¾né, e pri praktickej realizáciik opísanému problému vôbec nemusí dôjs. Pouitáimplementácia JVM môe vyhodnotenie výrazu vykonaatomicky alebo budú okolnosti nato¾ko priaznivé, ek iadnej chybe nedôjde. To však vo všeobecnosti oèaká-va nemôeme – vdy treba ráta s najhorším monýmprípadom. Programátor, ktorý sa spolieha na náhodu, sinezaslúi niè iné, len svoje programy za trest pouíva.

Ak chce zvedavý èitate¾ vidie efekt vzájomného „leze-nia do kapusty“ na vlastné oèi, staèí inkriminovaný výrazrozpísa napríklad takto:

int x_tmp = x;

 yield();x = x_tmp + 1;

Uvedené tri riadky simulujú vyhodnotenie pôvodnéhovýrazu s vynúteným preplánovaním na druhý threadmedzi naèítaním starej a uloením novej hodnoty x.Výsledná hodnota x bude pravdepodobne 10.

Tento príklad len jemne naznaèuje celú sféru problé-mov, ktoré môu vzniknú pri súbenej èinnosti viace-rých threadov a procesov. Riešenie spoèíva v pouití nie-ktorej zo synchronizaèných metód. Rozsah èlánku,bohuia¾, nedovo¾uje zaobera sa týmito metódami pod-robnejšie, pretoe ide o ve¾mi rozsiahlu (ale o to zaují-mavejšiu) tému. Pozrime sa preto len na monosti, ktoréna vyriešenie synchronizaèných problémov poskytuje

 Java.

Príkaz synchronizedÚsek kódu, ktorý by sa mal vykonáva atomicky, t. j.maximálne jedným threadom súèasne, nazveme v súlades tradíciami kritickou sekciou. Vylúèi súèasnú prítomnos

PC REVUE 33

JAVA POD LUPOU

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 34/36

viacerých threadov v kritickej sekcii je jednoduché: nepo-volíme do nej vstup v prípade, e sa tam nachádza inýthread. Je, samozrejme, nevyhnutné, aby thready predvstupom do kritickej sekcie svoj úmysel dali najavo.

Existuje mnoho spôsobov, ako zabezpeèi toto tzv.vzájomné vyluèovanie (mutual exclusion). Java pouívazámky (locks) a z nich vychádzajúcu implementáciumonitorov (pozri ïalej). Zámok je metaobjekt, ktorý nie jepriamo prístupný programátorovi a viae sa vdy na exis-

tujúci objekt (to, mimochodom, znamená, e pomocouprimitívnych typov zamyka nemono). Pre kadú kritic-kú sekciu v programe by mal existova samostatnýzámok.

Pred vstupom do kritickej sekcie sa thread pokúsizíska zámok nad vybraným objektom. Ak sa mu topodarí, zámok sa uzamkne a thread môe vykonáva kódkritickej oblasti. Ak sa mu to nepodarí, pretoe zámok jeu zamknutý, znamená to, e v kritickej oblasti je niektoiný. Thread bude preto pozastavený a opä sa rozbehnea po odomknutí zámku. Nevstupuje však do kritickejsekcie automaticky, ale opakuje svoj pokus o získaniezámku. Medzi okamihom, keï thread prešiel zo spiacehostavu do stavu pripravenosti, a okamihom, keï mu bolpridelený procesor, toti mohol do kritickej sekcie vstúpi

ïalší thread (hoci aj ten istý, èo v nej bol predtým). e tonie je spravodlivé? Nu, v paralelnom prostredí si prílišnenavyberáme…

V zdrojovom kóde kritickú sekciu musíme „obali“ dopríkazu synchronized. Ten má nasledujúcu syntax:

synchronized ( výraz ){

telo (kritická sekcia)}

Výsledkom výrazu musí by nenulová referencia na exis-tujúci objekt. Pred zaèatím vykonávania tela príkazu sathread pokúsi získa zámok nad týmto objektom. Akozamykací objekt pouijeme niektorý z objektov, s ktorý-

mi pracujeme v kritickej sekcii, alebo si vypomôemepomocným objektom:Object lock = new Object();synchronized (lock){

...}

Sémantika zamykania objektov v Jave dovo¾uje threadu,ktorý vlastní zámok nad nejakým objektom, získa tentozámok ešte raz. To je dôleité napríklad v takomto prípa-de:

synchronized (lock){

synchronized (lock){

 // ...}

}

Thread sa nezasekne na druhom príkaze synchronized,ale plynule prejde do kritickej sekcie.

 Dôleitá poznámka: Je nevyhnutné zabezpeèi, aby sak premenným a objektom, s ktorými pracujeme v kritic-kej sekcii, dalo v programe pristupova len cez príkazysynchronized, ktoré navyše musia pracova s rovnakýmzamykacím objektom. V opaènom prípade synchronizá-cia stráca zmysel.

MonitoryV paralelnom programovaní pojem monitor opisuje úda-

 jovú metaštruktúru, ktorú by sme mohli pripodobnik javovskej triede: monitor má vnútorný stav (údajovéèleny) a poskytuje operácie, ktoré mono nad monitoromvykonáva (metódy). Podstatným rozdielom oproti trie-dam je zabezpeèenie vzájomného vyluèovania pri prístu-pe k monitoru. Inak povedané: z metód monitora môe

by súèasne volaná najviac jedna.Implementácia monitorov v Jave je logickým dôsled-

kom pouitia mechanizmu zámkov. Ak sa zamyslíme nadtým, ako by sa dalo vzájomné vyluèovanie pri prístupek metódam triedy realizova, rýchlo prídeme na najjed-noduchšiu monos: obali kód metódy do príkazu syn-chronized a ako zamykací objekt poui this. Ide to všakešte jednoduchšie. Ak pri deklarácii metódy pouijemeako jeden z modifikátorov k¾úèové slovo synchronized,

dosiahneme tým, e pri volaní metódy sa aktuálny thre-ad najprv pokúsi získa zámok nad objektom, nad ktorýmmetódu volá. V prípade, e ide o statickú metódu, v rámciktorej objekt this neexistuje, ako zamykací objekt sapouije objekt typu Class reprezentujúci danú triedu.

Ako jednoduchý príklad monitora si ukáme triedu,ktorá vyrieši náš predchádzajúci problém s paralelnouinkrementáciou premennej x:

class MutExVar{

private int value;public MutExVar(int _val){ value = _val; }public synchronized void set(int _val){ value = _val; }

public synchronized int get(){ return value; }public synchronized void inc(){ value ++; }

}

Oba thready budú namiesto príkazu x = x + 1 v cyklevola metódu x.inc() (predpokladáme, e x  je teraz inš-tanciou triedy MutExVar ). Ïalšie synchronizované metó-dy set() a get() slúia na nastavenie a získanie uloenejhodnoty. Konštruktor z pochopite¾ných dôvodov nemusíby synchronizovaný.

Problém s deadlockomPri práci so zámkami sa treba vyvarova situácie, ktorá sabene oznaèuje anglickým termínom deadlock, po sloven-

sky uviaznutie. Okolo problému deadlocku existuje celáteória, take len struène: stav deadlocku znamená, e jeden alebo viacero threadov neobmedzene dlho èaká navstup do kritickej sekcie (a nikdy sa do nej nedostane).

Ako môe k deadlocku dôjs? Predstavme si dva thre-ady, ktoré na vstup do kritickej sekcie potrebujú získadva zámky, ale budú to robi v navzájom opaènom pora-dí. Prvý thread napríklad takto:

synchronized (lock1){

synchronized (lock2){ // ...

}}

a druhý takto:

synchronized (lock2){

synchronized (lock1){ // ...

}}

Ak sa prvému threadu podarí získa lock1 a druhémulock2, v tom okamihu sú odsúdení na veèné èakanie,pretoe ani jeden nemôe získa druhý zámok (má ho tendruhý). Vyriešenie tohto konkrétneho problému je jedno-duché – staèí zameni poradie príkazov synchronized

v niektorom z threadov. Univerzálny liek však na odstrá-nenie nebezpeèenstva deadlocku neexistuje a pri písaníprogramov treba pouíva predovšetkým zdravý rozuma riadnu dávku predstavivosti.

Podmieneèné premenné Java poskytuje ešte jeden synchronizaèný prostriedok,ktorý sa najviac podobá konceptu podmieneèných premen-

ných (conditional variables). Tie si môeme predstavi akometaobjekty, ktoré predstavujú synchronizaèné body via-zané na splnenie nejakej podmienky. Poskytujú dveoperácie s tradiènými názvami  wait  a  signal, ktorýmv Jave zodpovedajú metódy wait() a notify(). Ide o metó-dy triedy Object, a teda ich môeme zavola nad kadou

inštanciou objektového typu.Aká je sémantika týchto dvoch operácií? Ak thread

zistí, e podmienka, ktorá je pridruená k podmieneènejpremennej, nie je splnená, vykoná operáciu  wait . Tým sazaradí do zoznamu èakate¾ov na danú podmieneènú pre-mennú, prejde do stavu „spiaci“ a naïalej nesúaí o pri-delenie procesora. Zo spánku ho môe zobudi iný thre-ad, ktorý nad podmieneènou premennou vykoná operá-ciu  signal. Dôsledkom tejto operácie je výber jednéhoz èakate¾ov a jeho zobudenie. Zobudený thread sa presú-va do stavu „pripravený“ a èaká na pridelenie procesora.Ak je zoznam èakate¾ov prázdny, operácia signal nemánijaký efekt.

Pozrime sa teraz na vec na úrovni zdrojového kódu.Operácii  wait  zodpovedá zavolanie metódy  wait() nad

¾ubovo¾ným objektom (ktorý nahrádza spomínanú pod-mieneènú premennú). Aktuálny thread musí nad týmtoobjektom vlastni zámok. V rámci vykonávania metódy jethread pozastavený a zámok sa mu odoberie (to je nevy-hnutný krok, pretoe inak by spiaci thread blokovalakýko¾vek prístup k synchronizaènému objektu). Pri vola-ní metódy  wait() mono ako volite¾ný argument zadamaximálny èas, poèas ktorého thread bude èaka nazobudenie.

Druhej operácii  signal zodpovedá metóda notify(),ktorú, pochopite¾ne, voláme nad rovnakým objektom akometódu wait(). Thread, ktorý metódu volá, tak obyèajneèiní preto, lebo zabezpeèil splnenie podmienkypridruenej k objektu. Ako dôsledok volania metódy noti-fy() sa zobudí jeden z èakajúcich threadov (ktorý to bude, je vecou implementácie). Ak nikto neèaká, metóda je bezefektu. Niekedy príde vhod zobudi všetky èakajúce thre-ady – vtedy pouijeme metódu notifyAll(), ktorá sa inakspráva ako metóda notify(). Metódy notify() a notifyAll()by mal vola len thread, ktorý je momentálne vlastníkomzámku nad synchronizaèným objektom.

Zobudený thread nezaène bea okamite. Je zaradenýdo radu threadov èakajúcich na naplánovanie a po pride-lení procesora sa najprv snaí získa zámok, ktorý mu bolpred pozastavením odobraný. Po získaní zámku ukonèívolanie metódy  wait() a pokraèuje nasledujúcim príka-zom. V prípade, e thread volal metódu wait() ako dôsle-dok nesplnenia nejakej podmienky, je ve¾mi dôleité testpodmienky zopakova , pretoe nie je zaruèené, e sa odokamihu zobudenia threadu po jeho opätovné napláno-vanie táto podmienka nezmenila. Namiesto kódu:

synchronized ( obj ){

if (! podmienka )

obj. wait();}

treba bezpodmieneène poui kód:

synchronized ( obj ){ while (! podmienka )

obj.wait();}

A ešte jedna poznámka na záver: Threadu sa poèas vyko-návania metódy  wait() odoberá len zámok na aktuálnyobjekt. Prípadné ïalšie zámky mu zostávajú a sú tak dob-rým kandidátom na vznik deadlocku.

34 PC REVUE

JAVA POD LUPOU

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 35/36

PríkladyZdrojové texty k príkladom mono tradiène nájs na we-bovej stránke PC REVUE. Nachádza sa tam okrem inéhoriešenie klasického problému synchronizácie prístupu kukoneènému bufferu (inak známeho aj ako problém pro-ducentov/konzumentov).

18.èas : DodatkyPosledná èas seriálu patrí nieko¾kým témam, ktoré niesú nato¾ko bené (vnorené a anonymné triedy) alebo unie sú také populárne (applety), bolo by však škoda neve-nova im aspoò nieko¾ko riadkov.

Applety Applet   je zdrobneninou slova application (teda nijaké„jabåèko“, ako sa mono niekde doèíta). V súèasnostiapplety ustupujú do pozadia, ale ešte nedávno boli nad-mieru populárne ako súèas webových stránok. A na-to¾ko, e to zaváòalo gýèom a zlým vkusom.

Applet je javovská aplikácia, ktorá nie je urèená nasamostatné fungovanie – na svoj beh potrebuje

hosovské prostredie, ktorým je typicky, ale nie výhradneinternetový prehliadaè. Na rozdiel od klasických aplikáciíapplet nemusí obsahova metódu main(). Jadrom appletu je trieda odvodená od štandardnej systémovej triedy java.applet.Applet. Trieda Applet  je potomkom grafic-kého komponentu java.awt.Panel, z èoho môeme dedu-kova, e applety disponujú grafickým rozhraním. S gra-fikou sa v rámci appletu pracuje rovnako ako pri inýchkomponentoch AWT: applet má definovaný manaérlayoutu, mono doò pridáva iné komponenty( java.awt.Panel je kontajnerom), definova obsluhu uda-lostí a pod. Na pamäti treba ma iba skutoènos, e hlav-né okno appletu, ako súèas hosovského prostredia,obyèajne nemôe meni svoju polohu. Na zmenu ve¾kostinájdeme v triede Applet metódu resize(), ktorá však

nezaruèuje, e túto zmenu hosovské prostredie povolí.ivotný cyklus appletu mono rozdeli do štyroch

metód: init(), start(), stop() a destroy(). Prvú metódu,init(), volá prostredie po natiahnutí appletu do pamäte.Metóda je volaná práve raz a je vhodné do nej vloi kódna inicializáciu appletu – alokáciu prostriedkov, vytvore-nie pomocných objektov, threadov a pod. „Spustenie“appletu má na starosti metóda start(), ktorú prostredievolá, keï je applet zobrazený a prístupný pouívate¾ovi.Ak sa applet dostane mimo zobrazenej plochy (napríkladodrolujeme webovú stránku) alebo je neprístupný inýmspôsobom, prostredie zavolá metódu stop(). Logicky sidomyslíme, e metódy start() a stop() sa najlepšie hodiana rozbehnutie a pozastavenie prípadných beiacichthreadov. Poslednú metódu destroy() volá prostrediepred odstránením appletu z pamäte (opä práve raz). Tre-ba však vzia do úvahy, e spôsob, ako a kedy hosovsképrostredie volá spomenuté metódy, je úplne otázkou jeho implementácie.

Applet disponuje metódami na zisovanie informáciío prostredí, v ktorom beí. Metóda getDocumentBase()vracia URL adresu dokumentu, v ktorom je appletvloený. Iná metóda, getCodeBase(), vracia URL adresusamotného appletu (môe by odlišná od dokumentuURL). Pomocou metódy getParameter() môe appletzisova svoje parametre, zadané ako súèas dokumentu,v ktorom je applet vloený. Metódu showStatus() appletvyuije na zmenu textu v stavovom riadku hosovskéhoprostredia. Ïalšie dve metódy, getImage() a

getAudioClip(), slúia na natiahnutie obrázka alebo zvu-kového súboru zo zadanej adresy URL. Zvukový súbormono prehra pomocou metódy play(). Posledná metó-da getAppletContext() vracia objekt implementujúci roz-hranie  java.applet.AppletContext, ktorého metódy slú-ia na interakciu s hosovským prostredím.

Ukákový appletUkáme si príklad jednoduchého appletu, ktorý vo svo- jom okne zobrazí text zadaný pomocou parametra:

public class Display extends java.applet.Applet{

private final String defaultText = "Hello, world!";private String text;

public void init()

{ text = getParameter("DisplayText");if (text == null) text = defaultText;

}

public void paint(java.awt.Graphics g){

setBackground(new java.awt.Color(0xFFECC0));g.drawString(text, 20, 30);

}}

Text, ktorý sa má zobrazi v okne appletu, zistíme pomo-cou metódy getParameter(). Vhodným miestom na jejpouitie je metóda init(). Ak náhodou parameter nie jezadaný, metóda getParameter() vráti null a applet zob-razí preddefinovaný text „Hello, world!“.

Stránka s appletom môe vyzera napríklad takto:

<!DOCTYPE html PUBLIC "−//W3C//DTD HTML 4.0Transitional//EN"><html><head><title>Display Applet</title></head><body>

<p>Here comes the Display applet:</p>

<object classid="java:Display.class" width="140px" height="60px"><param name="DisplayText" value="Any other text"></object>

</body></html>

V starších materiáloch sa mono stretnú s vkladanímappletov do stránky pomocou elementu APPLET. Ten jeu pekných pár rôèkov povaovaný za zastaraný (depre-cated) a pod¾a špecifikácie HTML 4.01 je na vkladanieobjektov urèený element OBJECT. Syntax tohto elementunebudeme opisova, informácie mono nájs na adresehttp://www.w3.org/TR/html401. Parameter appletu za-dáme pomocou elementu PARAM.

Èitate¾ sa môe pokúsi prerobi applet tak, aby ajfarbu jeho pozadia bolo moné zada pomocou paramet-ra. Metóda getParameter() však vracia reazec, ktorý je

potrebné vhodne konvertova, pod¾a pouitého konštruk-tora triedy Color .

Obmedzenia appletovNa applety sa vzahujú urèité obmedzenia. Applet naprí-klad nemôe vytvori sieové spojenie s iným poèítaèom,ne z ktorého bol natiahnutý jeho kód. V prípade, eapplet pouíva ïalšie triedy, musia by tieto triedyumiestnené na rovnakom serveri. Je, samozrejme, monéma stránku a applet na rôznych serveroch – umiestnenieappletu potom treba spresni pomocou atribútu codeba-se elementu OBJECT. Ak sa poèas behu appletu pouívaviac ako jedna trieda, je vhodné celý balík transformovado archívu JAR a v stránke sa odvoláva na tento archív(ušetríme daèo z prenosovej kapacity, pretoe sa bude

sahova menší objem dát).Pri ladení appletov je dobré ma na pamäti, e pre-hliadaèe si natiahnutý kód ukladajú do pamäte cachea po opätovnom preklade zdrojového textu triedy obyèaj-ne nestaèí znovu natiahnu stránku s appletom; trebaprehliadaè ukonèi a znovu spusti.

Statické inicializátoryZa skonštruovanie inštancie triedy je zodpovedná špe-ciálna metóda, konštruktor. Kto sa však postará o inicia-lizáciu statických zloiek triedy? Dosia¾ sme mlèky pred-pokladali, e tieto zloky inicializujeme triviálnym spô-sobom ako súèas deklarácie:

static int x = 1;

Niekedy však jeden riadok kódu nestaèí: potrebovali bysme nejakú analógiu konštruktora, ale pre statické èleny.Takýto „statický konštruktor“ nazývame statickým ini-cializátorom. V deklarácii triedy sa môe statický inicia-

lizátor nachádza aj viackrát a poznáme ho pod¾a k¾úèo-vého slova static nasledovaného zloeným príkazom:

static{ // inicializácia...

}

Kód statických inicializátorov sa nachádza na rovnakejdeklaraènej úrovni ako kód ostatných metód. Aktivuje sapo natiahnutí triedy do pamäte pri prvom pokuse o vy-tvorenie inštancie triedy. Ak trieda obsahuje viac static-

kých inicializátorov, ich kódy sa vykonajú sekvenène,v takom poradí, v akom sa inicializátory nachádzajúv zdrojovom texte.

Statické vnorené triedyA do tejto chvíle sme v príkladoch pracovali s triedami,ktoré boli deklarované na súborovej (najvyššej) úrovni.V ïalšom texte ich budeme oznaèova ako top-level trie-dy. Java však dovo¾uje pouíva aj vnorené triedy(nested), deklarované v rámci inej triedy alebo dokoncav rámci metódy.

Pri triedach deklarovaných v rámci inej triedy hrá roluprítomnos èi neprítomnos modifikátora static. Vnorenétriedy, deklarované ako statické, sa v zásade nelíšia odtop-level tried. Pouívame ich rovnakým spôsobom a naich obsah sa nevzahujú nijaké obmedzenia. Jediným roz-dielom je ich plne kvalifikovaný názov: medzi „balíkovú“identifikáciu a názov vnorenej triedy musíme doplniešte názov tzv. obklopujúcej (enclosing) triedy, t. j. trie-dy, v ktorej je vnorená trieda deklarovaná. Príklad:

package my.pkg;class TopLevel{ // ...public static class Nested{ ... }

}

Vnorená trieda Nested  je súèasou obklopujúcej triedyTopLevel. Plne kvalifikovaný názov vnorenej triedy jemy.pkg.TopLevel.Nested. Ak vhodne pouijeme príkazimport alebo sa pohybujeme v rámci implicitného balíka,úplný názov triedy je TopLevel.Nested.

Statická vnorená trieda nesmie by deklarovaná indeako v top-level triede. Iné triedy môu k vnorenej triedepristupova pod¾a toho, ktorý modifikátor prístupu (pub-lic, protected, private) pri deklarácii tejto triedy po-uijeme. Obklopujúca trieda má k vnorenej triede vdyplný prístup. Statická vnorená trieda môe pristupovalen k statickým premenným a metódam obklopujúcejtriedy.

Èlenské triedyVnorené triedy, deklarované bez k¾úèového slova static,

sa nazývajú èlenskými triedami. Èlenské triedy majú narozdiel od statických vnorených tried prístup ku všetkýmèlenom a metódam obklopujúcej triedy. To je monévïaka obmedzeniu, pod¾a ktorého kadá inštancia èlen-skej triedy je zviazaná práve s jednou inštanciou obklo-pujúcej triedy (tzv. obklopujúcou inštanciou). Pri vytvára-ní inštancie èlenskej triedy dostane jej konštruktor refe-

PC REVUE 35

JAVA POD LUPOU

7/25/2019 Java SK

http://slidepdf.com/reader/full/java-sk 36/36

renciu na obklopujúcu inštanciu prostredníctvom skry-tého parametra. Logicky môeme usúdi, e vytvorenieinštancie èlenskej triedy je moné len v niektorej z metódobklopujúcej triedy.

Prístup k èlenským triedam „zvonka“ je riadený po-dobne ako v predchádzajúcom prípade modifikátormiprístupu. V rámci èlenských tried nemono deklarovastatické premenné, metódy ani inicializátory, s výnimkoustatických konštánt (deklarovaných s modifikátorom

final).

Lokálne triedyDeklarácia vnorenej triedy môe by takisto súèasou telametódy (nazvime ju obklopujúcou metódou). Takejto trie-de hovoríme lokálna. Inštancia lokálnej triedy je vidite¾nálen v rámci tela obklopujúcej metódy. Lokálna trieda máprístup ku všetkým premenným a metódam obklopujúcejtriedy (rovnaký princíp ako pri èlenských metódach).Okrem toho môe lokálna trieda pristupova k lokálnympremenným a parametrom obklopujúcej metódy za pod-mienky, e sú tieto premenné èi parametre deklarovanés modifikátorom final. Doba platnosti lokálnych premen-ných sa predluje na neurèito, pokia¾ existuje inštancialokálnej triedy, ktorá sa na ne odvoláva.

Lokálne triedy mono vhodne poui pri obsluhe uda-lostí ako tzv. adaptérové triedy. Vráme sa o jedno èi dveèísla èasopisu naspä a spomeòme si, e komponenty GUIumoòujú iným objektom „prihlási sa“ na odber ozná-mení o výskyte udalostí. Interakcia je zabezpeèená pomo-cou listenerov, èo sú špeciálne objekty implementujúcevybrané rozhranie. Komponent GUI pri výskyte „svojej“udalosti postupne zavolá príslušné metódy všetkých pri-hlásených listenerov. Objekty pracujúce v úlohe listene-rov sú obyèajne inštanciami vnorených tried: èlenských,lokálnych èi anonymných (pozri ïalej).

Príklad pouitia lokálnej triedy pri reakcii na stlaèenietlaèidla:

public void setUpButton()

{final Button b; b = new Button("Any text"); b.addActionListener(new ButtonListener());add(b);

class ButtonListener implements ActionListener{

public void actionPerformed(ActionEvent e){ b.setLabel("Clicked!"); }

}}

Metóda setUpButton() slúi na vytvorenie tlaèidla (triedaButton) a jeho pridanie do kontajnera (metóda add();treba si predstavi, e metóda setUpButton() je súèasou

objektu kontajnera). Pomocou metódyaddActionListener() pridáme k tlaèidlu listener – inštan-ciu lokálnej triedy ButtonListener . V rámci obsluhy uda-losti sa vyvolá metóda actionPerformed() tejto triedy.Metóda má prístup k objektu tlaèidla pomocou finálnejpremennej b, èo demonštrujeme zmenou textu tlaèidla.

Anonymné triedyVariáciou na lokálne triedy sú anonymné triedy. Nemajúvlastný názov, nesmú obsahova konštruktor a sú urèenéna ad hoc pouitie spájajúce deklaráciu s vytvorením inš-tancie. Deklarácia anonymnej triedy nahradzuje názovtypu vo výraze pre alokáciu nového objektu. Predchá-dzajúci príklad s vyuitím anonymnej triedy bude vyze-ra takto:

public void setUpButton(){

final Button b; b = new Button("Any text"); b.addActionListener(new ActionListener(){

public void actionPerformed(ActionEvent e){ b.setLabel("Clicked!"); }

});add(b);

}

Všimnime si, e za k¾úèovým slovom new sa nachádzanázov rozhrania ActionListener . Anonymná trieda budepotomkom triedy Object implementujúcim toto rozhra-

nie. Ak namiesto rozhrania uvedieme triedu, anonymnátrieda bude potomkom tejto triedy.

Implementácia vnorených triedBinárny kód javovských tried je uloený v súboroch s prí-

ponou .class. Názov kadého súboru je (bez prípony)totoný s názvom príslušnej triedy. Pre vnorené triedyvšak tento mechanizmus treba upravi, pretoe dve vno-rené triedy v rámci jedného balíka sa môu vola rovna-ko, ak sú deklarované v rôznych triedach.

Riešenie je jednoduché: názov súboru vznikne spoje-ním mena obklopujúcej triedy a vnorenej triedy. Obemená sú oddelené znakom $. Trieda TopLevel.Nestedz vyššie uvedeného odseku bude napríklad uloená v sú-

bore s názvom TopLevel$Nested.class. Rovnaké pravidloplatí pre triedy èlenské i lokálne.

Malý háèik predstavujú anonymné triedy: tie nemajúmeno, preto ich prekladaè pri preklade oèísluje vo vzo-stupnom poradí od jednotky a tieto èísla pouije ako„názvy“ tried na úèely vytvorenia mena binárneho súbo-ru. Ak teda budeme ma napríklad triedu MyClass a v nejdve anonymné triedy, prekladaè vygeneruje tri binárnesúbory:

MyClass.classMyClass$1.classMyClass$2.class

Ak je vnorená trieda súèasou inej vnorenej triedy, uve-dené pravidlo sa uplatní rekurzívne. Môeme sa potomstretnú hoci so súboromOuter$FirstLevel$SecondLevel$Inner.class.

KoniecSeriál je na konci. V Jave ako jazyku toho ve¾a nezostáva,a ak, tak len najpokroèilejšie témy, v praxi málokedypouívané. Väèší priestor ponúka Java ako platforma - tosme si však vysvetlili na úvod predošlej èasti: opis ïalšíchbalíkov by zabral prive¾a miesta a sotva by bol dostatoè-ne uitoèný, azda len ako slovenský preklad originálnejdokumentácie. Zostáva teda veri, e èitate¾ za svojepeniaze dostal adekvátnu protihodnotu a e programáto-rov, ktorí sa vedia orientova v Jave, je vïaka seriálu onieèo viac.

Vladimír Klimovský

JAVA POD LUPOU