Rozhraní (interface) je množina metod, která může být implementována třídou. Interface pouze popisuje metody, jejich vlastní implementace však neobsahuje. V Javě na rozdíl od jiných programovacích jazyků (například C++) nemůže třída dědit od více tříd najednou (neexistuje vícenásobná dědičnost). Každá třída však může implementovat libovolný počet rozhraní, do jisté míry tedy rozhraní vícenásobnou dědičnost nahrazují. Implementace rozhraní není na hierarchii tříd nijak vázána a nevzniká z ní vztah dědičnosti.
Definice rozhraní
Hlavička se skládá z modifikátoru viditelnosti (public), klíčového slova interface a jména rozhraní. Vlastní tělo definice pak obsahuje definici metod rozhraní.
Rozhraní může kromě definic metod obsahovat konstanty. Ty se pak chovají stejně, jako by se jednalo o konstanty třídy, která toto rozhraní implementovala. Podobně jako lze pomocí dědičnosti rozšiřovat třídy, lze rozšiřovat i rozhraní. Pokud vytvoříte rozhraní, které dědí od jiného rozhraní, automaticky tak přebírá všechny jeho metody a konstanty. Dědičnost rozhraní se zapisuje klíčovým slovem extends. Rozhraní také mohou dědit od více rozhraní najednou.
Implementovat rozhraní znamená implementovat všechny metody, které toto rozhraní definuje. Pokud třída implementuje nějaké rozhraní, je tím zaručeno, že obsahuje definici všech, které rozhraní definuje. Implementace rozhraní se uvádí v záhlaví definice třídy klíčovým slovem implements.
Třída může implementovat libovolný počet rozhraní, jak ukazuje následující příklad:
Použití rozhraní jako typů
V Javě lze definovat proměnnou typu reference na rozhraní, ve které může být uložena libovolná třída, která toto rozhraní implementuje. Jména rozhraní lze používat jako referenční datové typy stejným způsobem jako jména tříd.
Příklady rozhraní
Pro psaní jednoduchých aplikací nebudete zpravidla potřebovat definovat vlastní rozhraní, určitě se však neobejdete bez použití (implementace) předdefinovaných rozhraní Javy. Tady je seznam některých standardních často používaných rozhraní jazyka Java: " java.awt.LayoutManager - toto rozhraní definuje metody, které jsou nezbytné k tomu, aby třída mohla uspořádat grafické objekty na ploše okna. Blíže se s ním setkáme v díle, který bude věnovaný knihovně AWT. " java.io.DataInput, java.io.DataOutput - tato rozhraní definují metody požadované, pokud objekt chce komunikovat pomocí proudů pro předávání primitivních datových typů nebo znakových dat. " java.lang.Runnable - toto rozhraní definuje metodu run, jejíž kód běží jako samostatné vlákno
Patří mezi relační operátory. Operátor instanceof porovnává, zda objekt je instancí dané třídy nebo rozhraní. Jeho syntaxe je: Pokud se dá již při překladu zjistit, že třídy zkoumané pomocí instanceOf() nemohou mít nic společného, skončí překlad chybou
S pojmem polymorfizmus se setkáme v každém objektově orientovaném programovacím jazyce.V programovacím jazyce se jedná o možnost volat stejné metody u různých objektů, aniž bychom věděli, jakého přesně jsou typu. Navíc může mít stejná metoda u různých objektů odlišný význam. To je možné díky tomu, že vždy známe společného předka těchto různých objektů. Tím může být třída, abstraktní třída nebo rozhraní
Předpokládejme, že máme třídu A a třídu B, která od A dědí. V třídě A definujeme funkci s názvem fce, ve třídě B pak tuto metodu přepíšeme metodou stejného jména a stejných parametrů. Pokud nyní založíme objekt typu B a vyvoláme metodu fce, spustí se metoda objektu B i v případě, že je objekt uložen v proměnné typu A.
Ilustrace předchozího tvrzení o polymorfismu:
Kompilátor Javy přitom v době kompilace nemůže vědět, zda v proměnné b (typu Osoba) je uložen objekt typu Osoba nebo objekt nějaké jeho podtřídy. Která metoda bude ve skutečnosti spuštěna se proto rozhoduje až dynamicky za běhu programu.
Praktický příklad
Další příklad polymorfismu, který uvedu, je z praxe a je velice intuitivní. Prvky uživatelského rozhraní (tlačítka, editační boxy, Comboboxy apod.) jsou všechny potomky třídy Component. Každé okno si uchovává jejich seznam, ale předem neví, jaké komponenty v bude okno obsahovat (můžeme si dokonce díky dědičnosti vytvořit vlastní komponenty). Jedná se tedy o seznam položek typu Component. Když má být okno překresleno, je potřeba překreslit všechny komponenty, proto se pro každou komponentu na seznamu zavolá metoda repaint (tato metoda je zděděná od objektu Component). Java tedy pro každou komponentu za běhu zjistí její typ a podle toho spustí patřičnou metodu repaint - Button.repaint(), ComboBox.repaint(), MojeKomponenta.repaint(), apod. Každá komponenta přitom kreslí něco jiného a tyto metody jsou tedy různé.
Pomocí mechanismu výjimek můžeme lépe reagovat na chybové a nestandardní stavy běhu programu. Místo toho, abyste po každém vykonaném příkazu kontrolovali chyby, které mohou nastat, umístíte ošetření chyb celého bloku kódu na jedno místo.
Výjimky v Javě jsou objekty, které jsou potomky objektu java.lang.Throwable. Tato třída má dvě podtřídy java.lang.Error a java.lang.Exception (pro obě se používá společný název výjimky). Pokud v programu dojde k výjimečnému stavu, vznikne objekt výjimky a program může na tuto výjimku reagovat, odchytit ji.
Třída java.lang.Error a její podtřídy obvykle představují vážné chyby při běhu, ze kterých se program nemůže zotavit, například nedostatek paměti či chyby virtuálního stroje. Tyto výjimky by aplikace neměla odchytávat a měly by vést ke skončení programu.
Třída java.lang.Exception a její podtřídy představují výjimky, ze kterých se lze zotavit a program by je měl odchytávat a ošetřovat. Například java.io.IOException indikuje chybu při vstupně-výstupních operacích nebo java.io.EOFException indikuje čtení za koncem souboru.
Ošetření výjimek
Výjimky se ošetřují pomocí konstrukce try-catch-finally. Blok za klíčovým slovem try obsahuje nebezpečný kód, ve kterém může dojít k výjimce. Za ním následuje žádný nebo více bloků catch, ve kterých jsou ošetřeny jednotlivé typy výjimek, které mohou nastat v bloku try. Nepovinný blok finally obsahuje kód, který je vždy spuštěn nezávisle na tom, jak dopadl blok try (zda proběhl bezchybně či skončil výjimkou).
Příklad použití výjimek:
Postup zpracování
Při vstupu do bloku try se příkazy vykonávají v pořadí, ve kterým jsou zapsány. Pokud vše proběhne bezchybně, je po bloku try spuštěn případný blok finally. Pokud v průběhu bloku try nastane výjimka, přeruší se jeho vykonávání. Pokud některá klausule catch ošetřuje daný typ výjimky, spustí se blok kódu první takové. Nakonec se spustí blok finally, pokud je přítomen. Za klíčovým slovem catch následuje v kulatých závorkách typ výjimky a jméno proměnné, která na ni bude odkazovat. Tato klausule odchytává pouze výjimky tohoto typu a jeho podtypů. Proměnná odkazující na výjimku je platná pouze v daném bloku catch. Pokud výjimku neodchytí blok, který ji vyhodil, výjimka se šíří k následujícímu ohraničujícímu bloku. Pokud se nedochytí ani v něm, propaguje se dále. Pokud se neodchytí nikde v metodě, šíří se do nadřazené metody (která tuto metodu vyvolala) a dále po struktuře volání metod směrem ven. Pokud výjimku neodchytí nikdo, dostane se až do metody main(), kde způsobí ukončení interpretu Javy.
Metody výjimek
V objektu java.lang.Throwable je definováno několik užitečných metod. Metoda getMessge() poskytuje krátkou zprávu čitelnou pro člověka (může být však rovna null). Metoda toString() vrátí název třídy dané výjimky a zprávu (výstup getMessage()). Metoda printStackTrace() vypíše (na chybový výstup) výstup metody toString(), dále pak zásobník volání metod aktuální v době chyby s názvy tříd, metod a čísly řádků, kde k chybě došlo.
Výstup může vypadat například takto:
Výstup by odpovídal tomuto objektu:
Deklarace výjimek
Je nutné, aby každá metoda, která může způsobit výjimku, ji buď odchytila nebo specifikovala, že tuto výjimku způsobuje. Používá se k tomu klíčové slovo throws v deklaraci metody. Příklad metody, která může způsobit výjimku:
Není nutné ošetřovat ani deklarovat výjimky (pod)typu java.lang.Error ani java.lang.RuntimeException, protože je může potenciálně vyvolat každá metoda a měly by vést k přerušení programu.
Vlastní výjimky
Pomocí klíčového slova throw můžeme vyvolávat také své vlastní výjimky (nebo standardní výjimky). Vlastní výjimku definujeme jako objekt dědící od objektu java.lang.Throwable nebo nějakého jeho podobjektu.
Příklad vytvoření objektu vlastní výjimky:
Poté můžeme tuto výjimku vyvolat takhle:
... parametr konstruktoru se stane zprávou, kterou lze získat metodou getMessage(). Pokud vyhodíte vlastní výjimku, zpracovává se stejným mechanismem jako standardní výjimky (konstrukcemi try-catch-finally a propagací po struktuře kódu).