17. diel - Rozhranie (interface) v Jave
V minulej lekcii, Diár s databázou v Jave - Metódy diára, výnimky a final, sme si predstavili metódy triedy
Diary
, krátko sme pozreli na výnimky a na kľúčové slovo
final
.
Dnes to bude opäť trochu teoretické, objavíme ďalšie tajomstvá objektovo orientovaného programovania, predstavíme si totiž rozhranie.
Rozhranie
Rozhraním objektu sa myslí to, ako je objekt viditeľný zvonku. Už vieme,
že objekt obsahuje nejaké metódy, tie môžu byť privátne alebo verejné.
Rozhranie objektu tvoria práve jeho verejné metódy, je to spôsob, akým s
určitým typom objektu môžeme komunikovať. Už sme niekoľkokrát mohli
vidieť, aké verejné metódy naša trieda ponúka, napr. u nášho bojovníka
do arény. Trieda Warrior
mala nasledujúce verejné metódy:
void attack(Warrior enemy)
,void defend(int hit)
,boolean isAlive()
,void setMessage(String message)
,String getLastMessage()
,String healthBar()
.
Ak si do nejakej premennej uložíme inštanciu bojovníka, môžeme na ňu
volať metódy ako attack()
alebo defend()
. To stále
nie je nič nové, však?
My si rozhranie môžeme deklarovať zvlášť a to podobným spôsobom ako napríklad triedu. Toto rozhranie potom použijeme ako dátový typ.
Všetko si vyskúšame, ale na niečom jednoduchšom, než je bojovník.
Vytvorme si nový projekt a nazvime ho InterfaceSample
. Pridáme si
nejakú jednoduchú triedu. Pretože by sa podľa môjho názoru mala teória
vysvetľovať na niečom jednoduchom, urobíme si triedu vtáka. Bude vedieť
pípať, dýchať a klovať. Pridajme si triedu Bird
, bude vyzerať
takto:
public class Bird { public void chirp() { System.out.println("♫ ♫ ♫"); } public void breathe() { System.out.println("Breathing..."); } public void peck() { System.out.println("Peck, peck!"); } }
Trieda je naozaj triviálna. Prejdime do hlavného súboru
InterfaceSample.java
s metódou main()
a vytvorme si
inštanciu vtáka:
Bird bird = new Bird();
Teraz napíšeme bird.
a necháme IDE, aby nám zobrazilo
metódy na triede (možno tiež vyvolať stlačením Ctrl +
space):
Vidíme, čo všetko môžeme na vtákovi volať. Sú tam samozrejme tie 3 metódy, čo sme v triede implementovali (plus ďalšie, ktoré majú objekty v základe).
Teraz vtákovi vytvoríme rozhranie. Využijeme na to kľúčové slovo
interface
(slovensky rozhranie). Pomenovanie rozhrania v Jave je
pomerne veda, my sa uspokojíme s názvom BirdInterface
:
Pravým tlačidlom klikneme na projekt a následne na položku New
-> Java Class. V okne, ktoré sa potom otvorí, prepneme
Class
na Interface
:
K projektu sa nám pridá prázdny interface. Do neho pridáme hlavičky metód, ktoré má dané rozhranie obsahovať. Samotnú implementáciu (kód metód) uvádzame až v triede, ktorá bude toto rozhranie implementovať. Rozhranie vytvára iba predpis metód, čo musí trieda implementovať.
Do rozhrania BirdInterface
teda pridáme hlavičky metód,
schválne jednu vynecháme a pridáme iba metódy na pípanie a dýchanie:
public interface BirdInterface { void chirp(); void breathe(); }
Modifikátor public
neuvádzame, pretože rozhranie obsahuje
vždy iba verejné metódy. Inak by to nemalo zmysel, rozhranie udáva, ako s
objektom zvonku pracovať.
Vráťme sa do InterfaceSample.java
a zmeňme riadok s premennou
bird
tak, aby už nebola typu Bird
, ale
BirdInterface
:
BirdInterface bird = new Bird();
Kódom vyššie hovoríme, že v premennej type BirdInterface
očakávame objekt, ktorý obsahuje tie metódy, čo sú v rozhraní. IDE nám
vynadá, pretože trieda Bird
zatiaľ rozhranie
BirdInterface
neobsahuje. Aj keď potrebné metódy má, nevie, že
rozhranie poskytuje. Presunieme sa do triedy Bird
a nastavíme jej,
že implementuje interface BirdInterface
. Urobíme to kľúčovým
slovom implements
:
public class Bird implements BirdInterface { // ...
Keď sa teraz vrátime do súboru InterfaceSample.java
, riadok s
premennou typu BirdInterface
je už v poriadku, trieda
Bird
korektne implementuje rozhranie BirdInterface
a
jej inštancia môže byť do premennej tohto typu uložená.
Skúsme teraz vymazať z triedy Bird
nejakú metódu, ktorú
rozhranie udáva, napríklad chirp()
. IDE nás upozorní, že
implementácia nie je kompletná. Vráťme ju zas späť.
Opäť pridáme riadok bird.
do metódy main()
v
súbore InterfaceSample.java
, IDE nám ponúkne nasledujúce
metódy:
Vidíme, že na inštanciu môžeme teraz volať iba metódy, ktoré
poskytuje rozhranie. To preto, že premenná bird
je už typu
BirdInterface
, nie Bird
. Metóda peck()
úplne chýba.
Na čo je to dobré? Výhod a využití je viacero, na prvé sme už prišli. Pomocou rozhrania dokážeme zjednodušiť rozhranie nejakého zložitého objektu a vystaviť len tú časť, ktorá sa nám v tom čase hodí.
Ešte dodám, že nemôžeme vytvoriť inštanciu z rozhrania, tento kód nebude fungovať:
// this code won't work BirdInterface bird = new BirdInterface();
Viacnásobná dedičnosť
Java (rovnako ako väčšina jazykov) nepodporuje viacnásobnú dedičnosť. Nemôžeme teda jednu triedu oddediť z niekoľkých iných tried. Je to hlavne z toho dôvodu, že môže vyvstať problém kolízie názvov metód v rôznych triedach, z ktorých dedíme. Viacnásobná dedičnosť sa často obchádza práve cez interface, pretože tých môžeme v triede implementovať toľko, koľko chceme. Umožňuje nám to s inštanciou potom pracovať určitým spôsobom a vôbec nás nezaujíma, akého typu objekt v skutočnosti je a čo všetko navyše obsahuje.
Pridajme si k projektu rozhranie LizardInterface
. Bude to
rozhranie jaštera. Ten bude vedieť tiež dýchať a ešte sa plaziť:
public interface LizardInterface { void crawl(); void breathe(); }
Vtákojašter
Vyskúšajme si "viacnásobnú dedičnosť", presnejšie implementáciu
viacerých rozhraní v jednej triede. Urobme si vtákojaštera. Pridajme k
projektu triedu Pterodactyl
. Bude implementovať rozhrania
BirdInterface
a LizardInterface
:
public class Pterodactyl implements LizardInterface, BirdInterface { }
Keď teraz klikneme na ikonu žiarovky, môžeme v kontextovom menu zvoliť možnosť Implement methods. IntelliJ nám automaticky do triedy vygeneruje potrebné metódy:
Po implementácii oboch rozhraní môže vyzerať kód triedy takto (závisí na použitom IDE):
public class Pterodactyl implements LizardInterface, BirdInterface { @Override public void crawl() { throw new UnsupportedOperationException("Not supported yet."); } @Override public void breathe() { throw new UnsupportedOperationException("Not supported yet."); } @Override public void chirp() { throw new UnsupportedOperationException("Not supported yet."); } }
Všimnite si, že IDE pridalo notáciu @Override
k metódam,
ktoré implementujú rozhranie. Je to tak prehľadnejšie a kľúčové slovo
@Override
si pripíšeme aj k metódam chirp()
a
breathe()
v triede Bird
.
Metódy v triede Pterodactyl
doimplementujeme:
@Override public void crawl() { System.out.println("I'm crawling..."); } @Override public void breathe() { System.out.println("I'm breathing..."); } @Override public void chirp() { System.out.println("♫ ♫♫ ♫ ♫ ♫♫"); }
Presuňme sa do InterfaceSample.java
a vytvorme si inštanciu
vtákojaštera:
Pterodactyl pterodactyl = new Pterodactyl();
Uistite sa, že má metódy ako vtáka, tak aj jaštera:
V budúcej lekcii, Pretypovanie a hierarchia objektov v Jave, sa naučíme ďalšie pokročilé techniky objektovo orientovaného programovania.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 13x (4.6 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Java