<< Interface-y (rozhrania) | Obsah | Modifikátory viditeľnosti >>
V doterajšom kurze sme používali len triedy s jednoduchými, zvyčajne slovenskými názvami. Mali sme korytnačky Turtle
, ale mali sme aj Film
y, či FilmVPocitaci
. Java je však stavaná na budovanie obrovských systémov s tisíckami tried rozložených cez desiatky projektov a knižníc. V takýchto megaprojektoch nie je nič výnimočné, keď nastane kolízia v názvoch tried.
Vezmime si reálny príklad: do projektu si zavedieme triedu reprezentujúcu atribút nejakého tovaru (Predávame televízory, ktoré majú atribút farba) a nazveme si ju správne po anglicky Attribute
. Lenže beda! Taká trieda už existuje, pretože niekde v hlbinách Javy sa nachádza trieda s rovnakým názvom, ktorou sa nastavujú atribúty tlačovej zostavy. A keď sa rozhodneme zaviesť do projektu knižnicu na spracovanie webových stránok, kde Attribute
reprezentuje syntaktický prvok jazyka HTML, máme problém.
Jedným z riešení by bola dohoda a premenovanie tried: náš atribút by sme premenovali na ObjectAttribute
, a druhý konflikt vyriešili dohodou s autorom knižnice pre spracovanie HTML. Problém však tkvie v nemožnosti dohodnúť sa s autormi Javy.
Našťastie, takýmto problémom možno ľahko predchádzať, pretože v Jave existujú balíčky.
V každom rozumnom operačnom systéme existuje adresárová štruktúra, ktorá udržiava poriadok v súboroch. Príklad z Windowsu:
c:\Users\Public\Music\Sample Music\Kalimba.mp3
hovorí, že máme súbor Kalimba.mp3
na disku C
v adresári Users\Public\Music\Sample Music
. Inak povedané, máme adresár Users
s podadresárom Public
, ktorý má podadresár Music
, atď. (Kto neverí, nech tam beží, príklad je prevzatý z Windows 7.)
Keby adresáre neexistovali (čo bol stav v praoperačných systémoch na 8-bitových počítačoch), veľmi rýchlo by nastal na disku chaos.
Balíčky plnia presne úlohu organizovanosti jednotlivých tried. Každá javovská trieda patrí do niektorého balíčka (tak ako každý súbor je v nejakom adresári) a samotné balíčky sú organizované v hierarchickej štruktúre (práve tak, ako adresár môže obsahovať ďalšie podadresáre). Každá trieda v Jave má úplný názov (fully qualified name), ktorý predstavuje ,,úplnú cestu" v hierarchii balíčkov.
Keď sme napríklad spomínali triedu File
, ktorá reprezentuje súbor, v skutočnosti sme sa rozprávali o triede s úplným názvom java.io.File
. Balíček java
má podbalíček io
, ktorý obsahuje triedu File
.
Asi je zjavné, že takáto štruktúra predchádza problémom z úvodu. Už nemusíme premenovávať triedy s konfliktnými názvami, stačí, že majú triedy rozličné úplné názvy. A naozaj:
javax.print.attribute.Attribute
org.htmlparser.Attribute
sk.upjs.ics.paz
, čiže bude mať názov sk.upjs.ics.paz.Attribute
Panuje úzus, že názvy balíčkov sa odvodzujú od webových adries vývojára, čím sa zaručí ich jednoznačnosť. (Keďže spadáme pod Ústav informatiky, ktorý má web ics.upjs.sk, je to vhodný kandidát na názov balíčka). Na rozdiel od webových adries sa cesta udáva v obrátenom poradí.
Každá trieda v Jave patrí do nejakého balíčka. Dokonca i úplne triviálna trieda
patrí do tzv. implicitného balíčka, ktorý sa nachádza na vrchole hierarchie (je analógiou koreňového adresára).
Ak chceme zaradiť triedu do balíčka, potrebujeme spraviť dve veci:
package
Vezmime si triedu Film
z predošlých príkladov a zaraďme ju do balíčka sk.upjs.ics.paz.filmy
. To dosiahneme klauzulou
Výsledná trieda bude vyzerať:
O vytvorenie adresárov a zaradenie do správneho balíčka a aj adresára (teda v našom prípade do adresára src/sk/upjs/ics/paz/filmy) sa nám postará Eclipse.
Vytvorme si najprv nový package cez pravý klik na názov projektu > new > package, kde zadáme názov package-u sk.upjs.ics.paz.filmy
. Následne si označíme všetky java súbory, ktoré chceme presunúť a metódou drag&drop ich presunieme na nové miesto. Môžeme sa pozrieť, že vo všetkých presunutých súboroch pribudol nový riadok
V bežnom kóde platí zásada, že vždy keď použijeme názov triedy (napr. v deklarácii dátového typu premennej), tak kompilátor predpokladá, že ide o meno triedy, ktorá sa nachádza v rovnakom balíčku.
V predošlých príkladoch s dedičnosťou filmov sme mali šesť tried: Film
, FilmNaDvd
, FilmNaPaske
, FilmVPocitaci
, ZoznamFilmov
a Spustac
. Skúsme zaradiť všetky triedy do balíčka sk.upjs.ics.paz.filmy
.
Ak potom v metóde main()
triedy Spustac
(teda triedy s plným menom sk.upjs.ics.paz.filmy.Spustac
) použijeme triedu FilmNaDvd
, kompilátor bude predpokladať, že chceme používať triedu sk.upjs.ics.paz.filmy.FilmNaDvd
. Inak povedané, pred názov triedy FilmNaDvd
si domyslí plnú cestu v balíčkoch. Kód
bude teda ekvivalentný kódu
Je však asi zjavné, že takýto kód by bol veľmi rýchlo neprehľadný a teda domýšľanie mien má svoju logiku a zmysel.
Ak chceme používať triedu z iného balíčka, nie je nič jednoduchšie, stačí ju uviesť pomocou jej plného názvu. Tento prístup je ľahký na pochopenie, ale nik to tak nerobí:
V triede sk.upjs.ics.paz.filmy.Spustac
používame triedu java.io.File
a teda sa na ňu musíme odkázať plným menom.
Tento prístup je prostý, pretože sa drží jasnej zásady: Ak chceš používať triedu z iného balíčka, musíš sa na ňu odkázať plným menom. Existujú však projekty, ktoré používajú mimoriadne dlhé názvy, a tento spôsob je pre nich fatálny:
Našťastie existuje idea importov, ktoré tento problém odstraňujú.
Pomocou importov je možné skrátiť zápis kilometrových názvov tried. Dajme si príklad:
Klauzula import java.io.File
hovorí, že akonáhle sa v kóde spomenie trieda File
, znamená to v skutočnosti triedu java.io.File
. Import dramaticky skracuje a sprehľadňuje zápisy využívajúce triedy v iných balíčkov.
Importy možno zoskupovať: ak trieda používa viacero importov z jedného balíčka:
možno zápis skrátiť na
Takýto zápis hovorí "importni všetky triedy z balíčka java.io
".
Pozor ale: hromadný import sa týka len tried z konkrétneho balíčka. Neimportuje ani triedy z nadradených balíčkov, ani z podbalíčkov!
Rovnako platí, že v importe sa dá použiť len jediná hviezdička: snaha o import všetkých balíčkov Javy zlyhá: java.*.*.*
Existujú dve situácie, keď import tried prebieha automaticky. Prvú sme si už spomínali: trieda, ktorá sa nachádza v rovnakom balíčku, nemusí byť importovaná.
Druhým prípadom sú triedy z balíčka java.lang
. Nemusíme teda importovať bežné Java triedy, teda String
(java.lang.String
), System
(java.lang.System
) a pod.
Trieda, ktorá nemá žiadnu deklaráciu package
patrí do implicitného balíčka na vrchole hierarchie. V rozumnej knižnici a projekte by sa však takéto triedy nemali nachádzať, a ak sa tak dialo, tak to bolo kvôli jednoduchosti a z didaktických dôvodov.
Implicitný balíček je síce zdanlivo jednoduchý, ale môže viesť k neporiadku a najmä ku konfliktom v názvoch, ktoré sme spomínali na začiatku. Trieda v tomto balíčku má ešte jednu nevýhodu: nemôže byť importovaná z tried zaradených v balíčkoch.