Upozornění pro čtenáře a uživatele této knihy
Všechna práva vyhrazena. Žádná část této tištěné či elektronické knihy nesmí být reprodukována ani šířena v papírové, elektronické či jiné podobě bez předchozího písemného souhlasu nakladatele. Neoprávněné užití této knihy bude trestně stíháno.

Rudolf Pecinovský

Java 8
Úvod do objektové architektury pro mírně pokročilé

TIRÁŽ TIŠTĚNÉ PUBLIKACE:

Vydala Grada Publishing, a.s.
U Průhonu 22, 170 00 Praha 7
tel.: +420 234 264 401, fax: +420 234 264 400
www.grada.cz
jako svou 5670. publikaci

Odborní lektoři:
doc. Ing. Pavel Herout, Ph.D.,
doc. MUDr. Jiří Kofránek, CSc.,
doc. Ing. Vojtěch Merunka, Ph.D.,
doc. Ing. Miroslav Virius, CSc.

Odpovědný redaktor: Martin Vondráček, Ladislava Soukupová
Návrh vnitřního layoutu: Rudolf Pecinovský
Zlom: Rudolf Pecinovský
Počet stran 656
První vydání, Praha 2014
Vytiskly Tiskárny Havlíčkův Brod, a.s.

V knize použité názvy mohou být ochrannými známkami nebo registrovanými ochrannými známkami příslušných vlastníků.

Copyright © Grada Publishing, a.s., 2014
Cover Photo © fotobanka Allphoto.cz

ISBN 978-80-247-4638-8

ELEKTRONICKÉ PUBLIKACE:

ISBN 978-80-247-9480-8 ve formátu PDF
ISBN 978-80-247-9481-5 ve formátu EPUB

Mé ženě Jarušce a dětem
Štěpánce, Pavlínce, Ivance a Michalovi

Skrytí spoluautoři

Při tvorbě takto rozsáhlé knihy se autor nemůže spolehnout pouze sám na sebe. Je známou věcí, že když po sobě autor čte svůj rukopis, čte velmi často to, co chtěl napsat, a ne to, co doopravdy napsal. S kontrolou jazykových chyb mu může pomoci redaktor a jazykový korektor. S kontrolou odborných zaškobrtnutí mu však musí pomoci někdo jiný.

S kontrolou odborné správnosti musí pomoci někdo, kdo je odborně na výši a odhalí, že se autor vyjadřuje nepřesně nebo dokonce chybně. S kontrolou srozumitelnosti výkladu musí zase pomoci někdo, kdo se chce látku naučit a je ochoten text podrobně pročíst a upozorňovat na místa, kde výkladu zcela nerozumí nebo se mu zdá, že by bylo vhodné ještě něco doplnit. Úplně dokonalé pak je, když váš text čte zkušený učitel, který umí odhalit nejenom oba výše popsané druhy nepřesností či dokonce chyb, ale také naznačit možná potenciální nedorozumění a dezinterpretace vzniklá z podobnosti vykládané látky s jinými oblastmi, o nichž se výklad nezmiňuje.

Měl jsem to štěstí, že se mi podařilo získat spolupracovníky (a tím i kritiky) ze všech tří zmiňovaných skupin. Všem bych jim chtěl tímto poděkovat. Řekl bych, že díky jejich připomínkám a doporučením je výsledný text kvalitnější.

Všechny tyto dobrovolné spolupracovníky vnímám jako spoluautory. Proto mi dovolte, abych je tu alespoň abecedně vyjmenoval – byli to: Milan Augustin, Tibor Bako, Jakub Hadam, Michael Charvát, Jiří Kofránek, Jiří Kubala, Petr Kuchař, David Král, Filip Malý, Nikolas Patrik, Jarmila Pavlíčková, Luboš Pavlíček, Josef Svoboda, Petr Vidrman, Martin Vondráček a Martin Žamberský.

Úvod

Otevíráte knížku, která vás chce naučit programovat moderním, objektově orientovaným stylem. Stylem, jímž se v dnešní době vyvíjí drtivá většina klíčových aplikací, ale k jehož výuce ještě řada škol nedospěla. Po nastudování této knížky budou proto mnozí z vás vědět o moderním programování víc než leckterý z vašich učitelů.

Komu je kniha určena

Kniha je určena programátorům, kteří potřebují získat hlubší vhled do problematiky objektově orientovaného programování a návrhu architektury objektově orientovaných programů. K jejímu studiu přitom nepotřebují žádné velké předběžné zkušenosti. Stačí znalosti na úrovni mých začátečnických učebnic.

Kniha je reakcí na nepřetržité nářky vedoucích programátorských týmů, kteří posílají nastoupivší absolventy do mých přeškolovacích kurzů. Stěžují si, že školy opouštějí možná skvělí kodéři, ale neschopní architekti, že tito absolventi znají několik programovacích jazyků a řadu užitečných frameworků, ale mají problém s návrhem kvalitní architektury zadávaného programu.

Většina škol, učebnic a výukových kurzů se soustředí především na výklad syntaxe probíraného programovacího jazyka a probrání hlavních knihoven používané platformy. Jejich autoři se soustřeďují na detaily v bláhové naději, že jejich studenti a čtenáři pak v průběhu následující praxe pochopí vyšší principy. Když se ve výukovém programu objeví kurzy návrhových vzorů, končí často jako defilé technik, jak to či ono šikovně zakódovat.

Koncepce knihy

Ve svých knihách se pokouším tento stereotyp změnit. Soustředím se především na předvádění toho, jak program navrhnout a probrat věci, které považuji za důležité a přitom je v jiných učebnicích většinou nenajdete. Přitom se pokouším vše demonstrovat na příkladech. Na rozdíl od některých učebnic se však nechci omezovat pouze na AHA-příklady, jejichž jediným cílem je, aby po jejich prostudování student prohlásil „Aha! Takto to funguje!“, i když se jim v některých chvílích nevyhnu. Snažím se ale co největší část látky demonstrovat na složitějších příkladech, které však nejsou zahlceny spoustou šumu, za který považuji kód, který se musí naprogramovat, i když s vykládanou látkou přímo nesouvisí. Dávám přitom přednost příkladům používajícím grafiku, protože jsou pro daný účel většinou nejnázornější.

Kniha je koncipována jako druhý díl knihy Java 7 – Učebnice objektové architektury pro začátečníky^1. Předpokládá proto, že znáte látku zhruba na úrovni prvního dílu. Protože ale očekávám, že knihu bude číst i řada čtenářů, kteří získali své první programátorské zkušenosti z jiných zdrojů, tak pro jistotu na počátku nejdůležitější věci velice stručně zopakuji.

Co se naučíte, uspořádání knihy

Snažil jsem se v knize soustředit na oblasti, které se do jiných knih nevešly, a přitom je jejich osvojení velmi důležité, protože jejich neznalost je v lepším případě příčinou těžkopádných řešení a v horším případě příčinou špatně odhalitelných chyb.

V první části nejprve bleskově zopakuji základní látku prvního dílu a pak vás seznámím s jedním ze tří nejpoužívanějších profesionálních vývojových prostředí: s prostředím NetBeans. V minulém dílu jsme pracovali s vývojovým prostředím BlueJ. To je sice asi nejlepší prostředí pro získání základních představ a návyků objektově orientovaného programování, ale pro profesionální práci se příliš nehodí. Protože je ale zvládnutí vývojového prostředí zhruba stejně náročné jako zvládnutí programovacího jazyka, je mu věnován celý zbytek první části. Naučíte se je konfigurovat, vytvářet v něm projekty a využívat jeho výhodných vlastností pro zefektivnění své práce.

V druhé části si postupně ukážeme různé programové konstrukce a postupy, které můžete využít při návrhu architektury projektu. Postupně se seznámíte s dalšími návrhovými vzory, osvojíte si definici interfejsů obsahujících definice metod včetně jejich implementace, dozvíte se o možnosti parametrizace datových typů a jejich vzájemném vnořování, naučíte se používat lambda-výrazy, které umožňují pracovat s částmi kódu jako s proměnnými, a získáte první zkušenosti s prací s kontejnery a datovody.

Ve třetí části se ponoříme do výkladu dědění implementace. Začneme podrobným výkladem zavádění objektů a tříd a budeme pokračovat základními vlastnostmi dědění implementace. Dozvíte se, jak vytvářet třídy, jejichž předky jsou jiné třídy, a hlavně na co si dát při konstrukci takovýchto tříd pozor. Pokusím se vám demonstrovat některé vlastnosti dědění na třídách, které dědění emulují využitím návrhového vzoru Dekorátor a předvedu vám, jak definovat společného rodiče skupině tříd, které mají některé společné vlastnosti.

Ve čtvrté, závěrečné části, vám představím algoritmické konstrukce, jejichž používání je sice postupně nahrazováno jinými technikami (ty probírají předchozí části učebnice), ale prozatím se bez nich stále ještě neobejdeme. Navíc se ve starších programech s některými novějšími konstrukcemi ani nesetkáte.

Programovací jazyk

Přestože má kniha ve svém názvu uveden jazyk Java, tak musím dopředu oznámit, že se nejedná o učebnici jazyka Java. Těch je k dispozici více než dost. Jedná se o učebnici objektově orientovaného programování a jazyk Java je zde používán jako jazyk, v němž jsou zapsány programy demonstrující probíranou látku. Tento jazyk jsem zvolil z několika důvodů:

Je to stále s odstupem nejpoužívanější objektově orientovaný jazyk. Programátoři v Javě jsou stále nejžádanější (a mají i jedny z nejvyšších platů).

Je to jazyk poskytující všechny klíčové konstrukce používané v moderním programování.

Vytvořené programy nejsou omezeny na jediný operační systém, ale můžete je přenášet mezi různými operačními systémy.

A vlastnost neocenitelná pro studium a začátečnické experimenty: nástroje pro vývoj všech druhů aplikací od čipových karet až po rozsáhlé aplikace běžící na několika počítačích můžete sehnat zdarma.

Potřebné vybavení

Pro úspěšné studium této knihy budete potřebovat:

chuť naučit se objektově programovat a výdrž v situacích, kdy se vám nebude zcela dařit,

rozumně výkonný počítač,

základní vývojovou sadu Javy (JDK) ve verzi 8 a vyšší, kterou si můžete stáhnout se stránek http://www.oracle.com/technetwork/java/javase/downloads.

vývojové prostředí NetBeans ve verzi 8 a vyšší, které si můžete stáhnout ze stránek https://netbeans.org.

doprovodné příklady, které si můžete stáhnout ze stránky knihy http://knihy.pecinovsky.cz/uoa2_j8.

Doprovodné projekty

Na stránce knihy na adrese http://knihy.pecinovsky.cz/uoa2_j8 najdete také soubor s generátorem projektů použitých v knize. Téměř každá kapitola má svůj doprovodný projekt. Některé kapitoly jich mají dokonce několik. Možná bude někomu připadat zbytečné vytváření takového množství projektů, když jsou jednotlivé sekce umísťovány do samostatných balíčků a řada projektů ve svém obsahu vychází z projektů předchozích, k nimž buď něco přidá a/nebo něco jiného drobně upraví. Důvodem tohoto uspořádání je snaha vyjít začátečníkům vstříc a umožnit jim v každé kapitole začít znovu s funkčním projektem nezávisle na tom, do jakého stavu přivedli projekt z kapitoly přechozí.

První díl byl určen pro naprosté začátečníky, kterým jsem se snažil vyjít vstříc, a protože vím, jaký problém s angličtinou má značná část studentů, používal jsem pro větší názornost české identifikátory. Pořízením této učebnice jste se přihlásili mezi pokročilejší programátory, a ti se bez znalosti angličtiny neobejdou. V této branži platí: programátor musí umět anglicky, anebo musí změnit zaměstnání. V tomto dílu jsou proto už všechny identifikátory anglicky. České zůstávají pouze dokumentační komentáře.

Doplňková literatura

Kniha je tlustá, ale ani tak se do ní nevešlo vše, co by bylo potřeba. Navíc se mi nechtělo podrobně rozebírat témata, která už jsem vysvětlil v publikaci, kterou si můžete zdarma stáhnout. Hovořím konkrétně o knize Java 5.0 – Novinky jazyka a upgrade aplikací, kterou si můžete zdarma stáhnout na mých webových stránkách na adrese http://knihy.pecinovsky.cz/java5novinky.

Kromě toho se na svých stránkách http://vyuka.pecinovsky.cz chystám postupně zveřejňovat materiály, které budu připravovat pro studenty a případné polotovary budoucích publikací. Když si uvědomím, že při psaní knih vychází honorář asi tak na 7 korun za hodinu práce, tak se domnívám, že nic neztratím, když budu budoucí texty poskytovat zdarma a ponechám na rozhodnutí čtenářů, zda si jich cení tak, že jsou za ně ochotni něco zaplatit.

Použité konvence

Místní nabídka

„Skrytí spoluautoři“, kteří četli vytvářený rukopis, mne upozornili na některé formulace, které je nebo jejich kolegy trochu zaskočily. Jednou z nich je termín místní nabídka, který se sice v počítačové literatuře používá od počátku devadesátých let, nicméně do programátorského slangu ještě nepronikl.

Opatrně proto připomenu, že budu-li někde hovořit o tom, že máte zadat nějaký příkaz v místní nabídce objektu Xyz, znamená to, že máte na tento objekt najet myší, stisknutím pravého tlačítka rozbalit jeho místní nabídku (anglicky context menu) a v ní zadat požadovaný příkaz.

Formátování

K tomu, abyste se v textu lépe vyznali a také abyste si vykládanou látku lépe zapamatovali, používám několik prostředků pro odlišení a zvýraznění textu.

Objekty První výskyt nějakého termínu a další texty, které chci zvýraznit, vysazuji tučně.

Názvy Názvy firem a jejich produktů vysazuji kurzivou. Kurzivou vysazuji také názvy kapitol, podkapitol a oddílů, na které se v textu odkazuji.

Citace Texty, které si můžete přečíst na displeji, např. názvy polí v dialogových oknech či názvy příkazů v nabídkách, vysazuji tučným bezpatkovým písmem.

Adresy Názvy souborů a internetové adresy vysazuji obyčejným bezpatkovým písmem.

Program Texty programů a jejich částí vysazuji neproporcionálním písmem.

Kromě částí textu, které považuji za důležité zvýraznit nebo alespoň odlišit od okolního textu, najdete v textu ještě řadu doplňujících poznámek a vysvětlivek. Všechny budou v jednotném rámečku, který bude označen ikonou charakterizující druh informace, kterou vám chce poznámka či vysvětlivka předat.

Symbol jin-jang bude uvozovat poznámky, s nimiž se setkáte na počátku každé kapitoly. Zde vám vždy prozradím, co se v dané kapitole naučíte.

Otevřená schránka s dopisy označuje informace o projektu, s nímž budeme v dalším textu pracovat, nebo v něm najdete vzorové řešení.

Obrázek knihy označuje poznámku týkající se používané terminologie. Tato poznámka většinou upozorňuje na další používané termíny označující stejnou skutečnost nebo na konvence, které se k probírané problematice vztahují. Seznam všech terminologických poznámek najdete v rejstříku pod heslem „terminologie“.

Obrázek počítače označuje zadání úkolu, který máte samostatně vypracovat. Seznam všech úloh najdete v rejstříku pod heslem „úloha“.

Píšící ruka označuje obyčejnou poznámku, která pouze doplňuje informace z hlavního proudu výkladu o nějakou zajímavost.

Ruka s hrozícím prstem upozorňuje na věci, které byste měli určitě vědět a na které byste si měli dát pozor, protože jejich zanedbání vás většinou dostane do problémů.

Usměváček vás bude upozorňovat na různé tipy, kterými můžete vylepšit svůj program nebo zefektivnit svoji práci.

Mračoun vás naopak bude upozorňovat na různá úskalí programovacího jazyka nebo programů, s nimiž budeme pracovat, a bude vám radit, jak se těmto nástrahám vyhnout či jak to zařídit, aby vám alespoň pokud možno nevadily.

Brýle označují tzv. „poznámky pro šťouraly“, v nichž se vás snažím seznámit s některými zajímavými vlastnostmi probírané konstrukce nebo upozorňuji na některé souvislosti, jejichž znalost však není k pochopení látky nezbytná.

Symbol znamení raka označuje poznámku popisující doprovodnou animaci (animovaný výklad), která se vás bude snažit naučit nějakou dovednost, která se špatně popisuje slovy.

Odbočka

Občas je potřeba vysvětlit něco, co nezapadá přímo do okolního textu. V takových případech používám podšeděný blok se silnou čarou po straně. Tento podšeděný blok je takovou drobnou odbočkou od ostatního výkladu. Nadpis podšeděného bloku pak najdete i v podrobném obsahu mezi nečíslovanými nadpisy.

1 Kniha je současně slibovaným druhým dílem starší učebnice OOP – Naučte se myslet a programovat objektově. Ta sice vyšla v jiném nakladatelství, ale protože dané nakladatelství nedokázalo před několikeré upomínky dostát svým závazkům, tak jsem z tvorby druhého dílu vycouval.

Část I:

Vývojové prostředí

Tato část vám nejprve připomene, co byste měli znát, abyste mohli bez problémů pokračovat ve čtení knihy. Pak vás postupně seznámí s vývojovým prostředím NetBeans a jeho základními vlastnostmi, které by vám mohly pomoci výrazně zefektivnit vývoj programů.

Kapitola 1
Co byste měli znát z prvního dílu

Co se v kapitole naučíte

V této kapitole si velmi stručně připomeneme, co jste se naučili v prvním dílu učebnice, a seznámím vás s několika termíny, které budeme v dalším textu používat.

1.1Přehled látky prvního dílu

V první verzi rukopisu této knihy jsem z minulého dílu převzal podkapitoly nazvané Shrnutí – co jsme se naučili, v nichž jsem na konci každé kapitoly vždy stručně vyjmenoval, co se v dané lekci probíralo. Přitom jsem s údivem zjistil, že tento velmi zhuštěný přehled má přes 30 stránek. To mne zaskočilo. I když jsem jej prošel a vyjmul vše, co se týkalo jen BlueJ a projektů vytvářených v prvním dílu, stále mi ještě připadal na úvodní kapitolu příliš velký.

Rozhodl jsem se proto, že původní text úvodní kapitoly vyjmu z učebnice, nepatrně jej upravím a vystavím v samostatném souboru na webových stránkách knihy, odkud si jej budou moci stáhnout a přečíst i ti, kteří první díl nečetli a rozhodli se začít rovnou tímto druhým dílem (zmíněný text najdete na stránce knihy). V dalším textu budu předpokládat, že vše, co je v onom stručném shrnutí uvedeno, již znáte a mohu na to plynule navázat.

Pro jistotu ale ještě v následujících pasážích připomenu některé klíčové termíny, které jsem v prvním dílu zavedl a které nemusí být zcela srozumitelné těm, kteří získávali prvotní informace z jiných zdrojů než z prvního dílu. Zkušenost totiž ukazuje, že řada studentů tyto termíny zaměňuje, směšuje a/nebo je špatně interpretuje. Stručný přehled klíčových termínů uvádím především proto, abyste v okamžiku, kdy narazíte na daný termín v textu, věděli, o čem hovořím.

1.2Definice × deklarace

Než začneme s vlastním opakováním, chtěl bych připomenout dva obecné jazykové termíny, které si studenti občas pletou, a to termíny deklarace a definice:

Deklarace je část kódu, v níž předem oznamujeme některé vlastnosti vytvářeného programu. Je to takové prohlášení. Účelem deklarace je poskytnout překladači informace, na jejichž základě pak může kontrolovat, jestli ve svém programu neděláte nějaké evidentní chyby.

Definice je část kódu, v níž něco doopravdy vytváříme. Jedná-li se o metodu, opravdu se někde objeví předpis definující, jak metoda pracuje. Jedná-li se o objekt, necháváme mu přidělit paměť a přiřadit počáteční hodnotu.

U datových objektů (proměnných a konstant) se často slučuje deklarace s definicí. Danou proměnnou deklarujeme (prozradíme, jaký bude mít datový typ a jak se bude jmenovat) a současně ji i definujeme (přiřadíme jí počáteční hodnotu, čímž donutíme překladač, aby pro ni vyhradil potřebnou paměť).

Klasické abstraktní metody, s nimiž se setkáme v interfejsech, jsou zde pouze deklarovány. V deklaraci pouze překladači vysvětlujeme, jakou by měla mít požadovaná metoda signaturu, jaká by měla být, kdyby ji někdo definoval.

Ve třídách jsme pak metody přímo definovali, protože jsme za hlavičkou metody zapisovali její tělo, v němž jsme popisovali, co má daná metoda dělat.

V tomto dílu se dozvíte, že situace není tak jednoduchá, jak se původně zdálo, tj. že se v interfejsech metody deklarovaly a ve třídách definovaly. Dozvíte se, že ve třídě můžete deklarovat abstraktní metodu a naopak v interfejsu definovat konkrétní metodu. K tomu všemu postupně dojdeme.

1.3Co je to objekt

Vraťme se ale k objektovému programování. Říkali jsme si, že každý program je simulací reálného nebo virtuálního světa. Tento svět je tvořen objekty, které jsou v programu reprezentovány stejně pojmenovanými daty. Jako objekt označujeme v programu kolekci dat reprezentující odpovídající objekt z onoho simulovaného světa.

Oproti běžnému chápání objektů v reálném světě je však v programu používán termín objekt mnohem obecněji: objekty v programu mohou reprezentovat cokoliv, co můžeme pojmenovat, tj. cokoliv, co můžeme označit podstatným jménem.

V programu proto chápeme jako objekty i vlastnosti (velikost, směr, krása), děje (připojení, přerušení, výpočet) a další pojmenovatelné entity. Objektem je proto i třída, rozhraní, metoda atd.

Malá poznámka pro ty, kteří mají zkušenosti s jazyky Turbo Pacal a Delphi. Jejich autor nám přichystal malý terminologický guláš, protože to, co zbytek světa označuje termínem třída, začal nazývat objekt. Možná proto budete chvíli zmateni, ale věřím, že jenom chvíli.

1.4Datový typ, třída, class-objekt

V programech se vyskytují celé skupiny objektů, které mají stejnou charakteristiku. Tuto charakteristiku označujeme jako datový typ oněch objektů. Objekty s charakteristikou definovanou nějakým datovým typem označujeme jako instance daného datového typu.

Datové typy lze rozdělit do několika skupin. Jazyk Java rozlišuje následující druhy datových typů:

Primitivní datové typy představují typy, které nejsou objektové (nemají své instance), ale zato mají přímou podporu v instrukčním souboru většiny procesorů. Nabourávají čistou objektovou orientovanost jazyka a byly do něj zavedeny pro zvýšení efektivity. Prozatím se bez nich neobejdeme, ale to by se mělo v některé z příštích verzí změnit.

Třídy představují základní druh objektového datového typu.

Výčtové typy jsou speciální třídy, které mají pouze předem definované instance, přičemž tuto množinu instancí není možno dále měnit.

Interfejsy představují datové typy reprezentující rozhraní instancí tříd, které tyto interfejsy implementují (podrobněji za chvíli).

Datové typy jsou zvláštním druhem objektů. V jazyce Java nejsou (na rozdíl např. od jazyka Smalltalk) instancí žádného datového typu. Můžeme je však oslovovat prostřednictvím speciálních zástupných objektů, které jsou instancemi třídy java.lang.Class (podrobněji se s nimi seznámíme v pasáži Třídy jako objekty – class-objekt třídy).

1.5Zpráva × metoda, polymorfismus

Objekty simulovaného světa spolu navzájem komunikují – fyzikálně, chemicky, biologicky, verbálně, společensky atd. Veškeré tyto interakce reprezentujeme v programu jako zasílání zpráv jednoho objektu jinému.

ZprávaTermínem zpráva označujeme požadavek, který zasílá jeden objekt druhému. Odesílatel zprávy přitom očekává od adresáta reakci odpovídající kontraktu dané zprávy (co je to kontrakt, si připomeneme za chvíli).

MetodaTermínem metoda označujeme kód definující, jak bude daný objekt reagovat na zaslanou zprávu.

Každá zpráva, na kterou umí objekt zareagovat, má přiřazenu metodu, v níž je definována požadovaná reakce objektu na zaslání dané zprávy. Některým zprávám ale může být přiřazeno více metod a to, která metoda se použije, záleží na různých věcech. Většina jazyků (a Java mezi nimi) odvozuje to, jaká metoda bude použita, od typu osloveného objektu; obecně to ale může záviset i na jiných věcech.

Schopnost objektů reagovat na stejnou zprávu různě označujeme jako polymorfismus. Takové chování ale pouze reprezentuje stav v onom světě simulovaném naším programem. Představte si např. nějaký sportovní zápas. Všichni v hledišti jsou instance typu Člověk. Nicméně na zprávu o vstřeleném gólu budou instance podtypu FanoušekTýmuA reagovat jinak než instance podtypu FanoušekTýmuB a opět jinak budou reagovat instance podtypu ProdavačkaNaTribuně.

1.6Rozhraní × interfejs

Pro ty, kteří nečetli minulý díl, bych připomněl, že v textu učebnice rozlišuji mezi termíny rozhraní a interfejs:

Rozhraní představuje množinu charakteristik, jimiž se daná entita (balíček, třída, metoda, atribut, …) prezentuje svému okolí, a které tím pádem okolí o dané entitě explicitně zná. Své rozhraní má každá entita programu.

Interfejs je programová konstrukce, kterou Java zavedla a kterou od ní mnohé další programovací jazyky převzaly. Díky interfejsu můžeme specifikovat požadavky na rozhraní objektů, s nimiž se chystáme pracovat.

Některé programátory irituje, že používám počeštěnou podobu anglického interface. V tištěném textu však musíme dávat přednost spisovným tvarům před slangovými. Převzaté slovo interface nelze skloňovat, a proto dávám přednost povolenému (viz Akademický slovník cizích slov. Academia Praha 1995. ISBN 80-200-0497-1) počeštěnému tvaru. Ostatně počeštění tvaru často používaných převzatých slov je běžné – podívejte se např. na slova fotbal, hokej či tenis.

V minulém dílu jsem navíc využil toho, že interfejs sloužil opravdu jenom k popisu požadovaného rozhraní, a pokud jsem se domníval, že nemůže dojít k nedorozumění, používal jsem český termín rozhraní i při označování dané programové konstrukce. To už si v tomto dílu nemohu dovolit, protože v Javě 8 přestal interfejs pouze deklarovat požadované rozhraní. Java 8 totiž umožňuje, abychom v interfejsu definovali i doporučenou implementaci (viz kapitolu 14 Implicitní implementace – RingVehicle, ControlledVehicle), a navíc může obsahovat i definice statických metod. Protože se nyní významy obou termínů vzdálily, budu jejich terminologické rozdělení důsledně dodržovat.

V souvislosti s rozhraním bych ještě připomněl další dva termíny: signatura a kontrakt:

Signatura označuje tu část rozhraní, kterou může zkontrolovat překladač. Sem patří např. název dané entity, její datový typ (případně typ metod návratové hodnoty), u metod typy jednotlivých parametrů a některé další překladačem kontrolovatelné charakteristiky.

Kontrakt označuje tu část rozhraní, kterou překladač zkontrolovat nedokáže – např. že šířka obdélníku nesmí být záporná. Kontrakt popisujeme v dokumentačních komentářích a za jeho dodržení je zodpovědný programátor. Za prvé tak, že sám kontrakty dodržuje, a za druhé tak, že za běhu programu kontroluje, že je dodržují i používané objekty (s jednou ověřovací konstrukcí se seznámíme v podkapitole 9.15 Ověřování podmínek – příkaz assert).

1.7Zapouzdření a skrývání implementace

Vedle rozhraní má každá entita programu svoji implementaci, která specifikuje, jak daná entita dosahuje funkčnosti deklarované v jejím rozhraní. Jedna z hlavních zásad správného programování doporučuje programovat tak, abyste v každé situaci využívali pouze znalostí rozhraní používané entity a nesnažili se vylepšit program díky znalostem její implementace.

Zásada se nejlépe dodržuje tak, že nemám šanci ji porušit. Proto moderní programovací jazyky umožňují maximálně skrývat implementační detaily.

V souvislosti se skrýváním implementace se často hovoří o zapouzdření. Tímto termínem byla původně označována skutečnost, že objektové programování zapouzdřuje do společného objektu data i kód, který s těmito daty pracuje. Postupem času původní význam termínu zapouzdření ustupoval do pozadí a stále častěji se tímto termínem označovalo především skrývání implementace. Podvolím se tomuto všeobecnému trendu a budu jej v tomto významu používat i v této učebnici.

1.8Datové typy a jejich dědění

V minulém dílu jsme se seznámili s konstrukcí dědění datových typů. Vysvětlili jsme si, že datový typ potomka specifikuje společné vlastnosti nějaké speciální podmnožiny instancí předka, přičemž objekty z této podmnožiny mají oproti ostatním instancím předka jisté speciální vlastnosti, kvůli nimž je pro ně vhodné definovat samostatný datový typ. Současně jsem vám prozradil, že existují tři typy dědění:

Přirozené (nativní) dědění hovoří o tom, jak specializaci objektů cítíme bez ohledu na to, jak ji naprogramujeme.

Ve škole jsme se např. učili, že čtverec je speciální případ obdélníku. Vysvětlovali jsme si, kdy můžeme tuto obecnou znalost promítnout do našeho programu, a kdy si to naopak dovolit nemůžeme.

Dědění typu odpovídá v programech dědění rozhraní. Toto dědění se uplatňuje nejen při dědění interfejsů, ale i při implementaci interfejsu třídou. Z hlediska dědění typů lze proto implementovaný interfejs považovat za jednoho z rodičů tříd, které jej implementují.

Připomínám, že dědění typů je o slibech. Když datový typ prohlásí, že dědí nějaký jiný typ, tak překladač může zkontrolovat pouze to, jestli dodržuje požadovanou signaturu. Na zodpovědnosti programátora pak je, aby vedle signatury dodržel i kontrakt, a splnil tak slib, který dal, když přihlašoval datový typ k dědění jeho rodiče. Nedodržení tohoto slibu je příčinou celé řady chyb.

Dědění implementace se uplatní při dědění tříd. Při něm třída od svého rodiče přebírá nejenom jeho rozhraní, ale překladač zabezpečí, že přebere také veškerou jeho implementaci. Nemusí tedy definovat pro všechno vlastní metody, ale v řadě případů může použít metodu zděděnou od svého rodiče či od některého z prarodičů.

V dědění implementace jsou skryty mnohé záludnosti (na některé z nich jsem v minulém dílu upozorňoval), a proto jsem jeho výklad odložil až do tohoto dílu. Budeme o něm hovořit ve třetí části, kdy budete mít větší zkušenosti, které vám za prvé pomohou:

odhalit situace, v nichž je použití dědění implementace nešikovné či přímo nevhodné (velmi oblíbená chyba, kterou dělají mnozí zdánlivě zkušení programátoři),

orientovat se v situacích, kdy je použití dědění implementace výhodné, ale hrozí při něm riziko zanesení „oblíbených“ chyb.

Má-li být náš program stabilní a v budoucnu snadno rozšiřitelný, musíme při dědění vždy respektovat všechny tři aspekty.

Vlastní instance třídy a mateřská třída objektu

Abych usnadnil orientaci v příslušnosti objektu k datovým typům, zavedl jsem ještě další dva termíny:

Vlastní instance třídy (anglicky class‘ own instance) je instance, kterou „porodila“ daná třída, a není proto instancí žádného z jejích potomků.

Mateřská třída objektu (anglicky home class). Je-li objekt vlastní instancí nějaké třídy, označujeme tuto třídu jako mateřskou třídu daného objektu.

LSP – Liskov Substitution Principle

Před chvílí jsem říkal, že odvozený typ specifikuje společné vlastnosti podmnožiny instancí předka. Z vlastnosti, že prvky podmnožiny nepřestávají být prvky původní množiny, vyplývá, že instance potomků nepřestávají být instancemi předka, a měly by proto být schopny kdykoliv vystupovat v roli instance kteréhokoliv ze svých předků.

Zásadu, že potomek musí být schopen kdykoliv plnohodnotně vystupovat v roli instance předka, formulovala v roce 1987 ve své přednášce^2 Barbora Liskov a od té doby je označována jako Liskov Substitution Principle (Substituční princip Liskové) a používá se pro ni zkratka LSP.

Bohužel, řada programátorů tuto zásadu ve svých programech porušuje, a pak se diví, proč jim jejich „dokonalé programy“ nechodí. S příklady porušujícími tuto zásadu se bohužel setkáte i v přednáškách řady universit (včetně těch nejprestižnějších) o učebnicích a kurzech programování ani nemluvě.

Přetěžování × přebíjení × zakrývání metod

V souvislosti s děděním bych připomněl další tři termíny, které si začátečníci občas pletou, a to přetěžování, přebíjení a zakrývání metod.

O přetěžování (anglicky overloading) metod hovoříme tehdy, definuje-li jeden datový typ několik metod se stejným názvem, ale rozdílnou signaturou.

O přebíjení (anglicky overriding) nebo překrývání metod hovoříme tehdy, definuje-li potomek metodu se stejnou signaturou, jako má některá z viditelných metod rodiče. Potomkova verze metody je přitom začleněna do definice objektu tak, aby se použila pokaždé, když potomkovi někdo pošle příslušnou zprávu, a to nezávisle na tom, za instanci jakého typu se v danou chvíli potomek vydává. Přebíjení se budeme podrobněji věnovat v kapitole 24 Virtuální metody a jejich přebíjení.

O zakrývání (anglicky hiding) metod hovoříme tehdy, pokud potomek definuje metodu se stejnou signaturou, jako má některá z metod jeho rodiče, avšak rodičovská metoda zůstává dostupná a to, která z metod se použije, záleží na tom, komu se daná zpráva posílá. V Javě je možno zakrývat pouze statické metody. Instanční metody je možné pouze přetížit či přebít. Zakrývání se budeme podrobněji věnovat v kapitole 23 Zakrývání atributů a metod.

Překlad přebít přesněji odpovídá anglickému originálu, a proto mu budu dávat přednost. V minulém dílu jsem si to ještě netroufl a dal na námitky kolegů, že takový termín je příliš lidový a do odborné terminologie nepatří. Pak jsem si ale řekl, že nemusíme být tak úzkoprsí. Když mohou být lidové výrazy v angličtině, proč bychom je nemohli mít v češtině. Angličan či Američan klidně označí programový modul termínem podniková fazole (enterprise bean). Našim programátorům z takového označení naskakuje kopřivka. Pokud máte s takovýmito termíny mentální problémy, doporučuji vám počkat si na vydání anglické verze této učebnice. Tam budu sice používat tytéž výrazy, ale v anglickém textu takovéto termíny nikoho neuráží.

1.9Odkazové a hodnotové datové typy

Objektové datové typy rozdělujeme na odkazové a hodnotové podle toho, jak přistupujeme k posouzení ekvivalence dvou instancí. Instance hodnotových datových typů reprezentují nějakou hodnotu a jejich dvě instance považujeme za ekvivalentní, pokud obě reprezentují stejnou hodnotu. Naproti tomu instance odkazových datových typů reprezentují nějaké jedinečné entity a jsou ekvivalentní pouze samy se sebou.

To, jestli je daný typ odkazový či hodnotový, poznáme snadno podle toho, definuje-li vlastní verzi metody equals(Object). Odkazové datové typy se spokojí s verzí zděděnou od třídy objekt, která je definovaná tak, že (stejně jako operátor ==) vracejí true pouze v případě, kdy porovnáváme instanci samu se sebou. V opačném případě vracejí false. U odkazových datových typů bývá tato informace opravdu tím, na co se chceme zeptat. U hodnotových datových typů nás ale většinou nezajímá porovnání instancí, ale porovnání jimi reprezentovaných hodnot, a proto musejí přebít zděděnou verzi verzí vlastní.

Tato poznámka je určena pro čtenáře, kteří mají zkušenosti s programováním v prostředí .NET. Tam totiž zavádějí terminologický guláš, protože typy nerozlišují podle toho, zda reprezentují hodnotu, ale podle způsobu alokace jejich instancí v paměti. Jako hodnotové datové typy označují typy, které se nealokují na haldě, ale na zásobníku návratových adres. To ale obecně nemusí být hodnotové typy, protože nemusejí představovat žádnou hodnotu. Tyto typy bychom mohli označit spíše jako kopírované, protože se u nich přiřazení realizuje zkopírováním daného objektu, a ne zkopírováním pouhého odkazu.

1.10Návrhové vzory

V minulém dílu jsme se seznámili s několika návrhovými vzory. V tomto dílu k nim přidáme další. Připomenu, že návrhové vzory jsou programátorské ekvivalenty matematických vzorečků, v nichž místo čísel vystupují objekty a datové typy. Jsou to doporučení, jak vyřešit některé často se vyskytující úlohy.

Zopakujme si alespoň ve stručnosti ty, které byste měli z minulého dílu znát (uvádím je v abecedním pořadí). Neznáte-li je, pokuste se před dalším čtením doplnit své znalosti.

Jedináček (singleton)
řeší problém třídy, která má mít právě jednu instanci

Jednoduchá tovární metoda (simple factory method)
je statická metoda vracející jako svoji funkční hodnotu instanci třídy, v níž je definována. Odstraňuje některé nevýhody konstruktoru, a proto ji některé datové typy používají místo konstruktoru.

Knihovní třída (library class, utility)
je třída, která nemá žádné instanční členy. Definuje pouze statické konstanty a metody. Protože nepotřebuje instance, je definována tak, aby její instance nešlo vytvořit.

Posluchač (listener)
navrhuje efektivní řešení situace, kdy jeden či více objektů čeká na výskyt nějaké události (např. stisk tlačítka), aby na ni mohly zareagovat.

Pozorovatel (observer)
je pouze jiný název pro návrhový vzor Posluchač.

Prázdný objekt (null object)
představuje nesmyslnou instanci své mateřské třídy a používá se v situacích, kdy metoda nemůže vrátit žádnou platnou instanci. Mnohé metody vracejí v takových situacích prázdný odkaz (null), ale tomu se pak nedají posílat zprávy a tím se komplikuje okolní program. Alternativní způsob řešení tohoto problému si naznačíme v podkapitole 30.3 Datový typ Optional<T>.

Prototyp (prototype)
nabízí alternativní způsob vytváření nových instancí jako kopií instancí již existujících.

Prostředník (mediator)
řeší problém přílišného množství vazeb mezi jednotlivými třídami zavedením prostředníka, který komunikaci mezi třídami či jejich instancemi zprostředkuje.

Služebník (servant)
řeší problém, jak dodat dodatečnou společnou funkcionalitu skupině tříd, aniž bychom museli do každé přidávat téměř shodnou metodu.

Vážení čtenáři, právě jste dočetli ukázku z knihy Java 8.
Pokud se Vám líbila, celou knihu si můžete zakoupit v našem e-shopu.