V programovacím jazyce Java se pro abstrakci využívají abstraktní třídy a rozhraní. Abstrakce, jako koncept v objektově orientovaném programování, spočívá v utajení detailů implementace před koncovými uživateli.
V rámci abstrakce víme, jaké funkce jsou k dispozici, avšak detaily jejich vnitřního fungování zůstávají skryty.
Pojďme se blíže podívat na oba tyto mechanismy a pochopit, k čemu slouží.
Abstraktní třída
Abstraktní třída je v jazyce Java taková třída, ze které nelze vytvořit objekt, a která může, ale nemusí obsahovat abstraktní metody. Abstraktní metoda je taková metoda, která nemá implementační tělo při svém deklarování.
Příklad abstraktní třídy je například `GraphicObject` v dokumentaci od Oracle.
Abstraktní třídu lze vytvořit pomocí klíčového slova `abstract` před klíčovým slovem `class`.
abstract class AbstractClass { void run() { System.out.println("ran"); } }
Abstraktní třída může být dále rozšiřována jinými třídami, čímž se stává tzv. nadtřídou pro tyto podtřídy.
abstract class AbstractClass { void run() { System.out.println("ran"); } } class ExtendingAbstractClass extends AbstractClass { void newMethod() { System.out.println("new"); } @Override void run() { System.out.println("override"); } }
Abstraktní třídy se často využívají pro sdílení společných metod mezi více třídami, které z dané abstraktní třídy dědí. Možnost definování abstraktních metod v rámci abstraktních tříd je činí velmi užitečnými pro případy, kdy máme třídy s podobnými metodami, ale s rozdílnou implementací. Podívejme se na praktický příklad.
Představme si automobil, který má základní funkce jako start, stop, couvání a podobně. Tyto funkce jsou společné pro všechny typy automobilů.
Ovšem, co se stane s funkcemi jako automatické řízení? Implementace této funkce se může mezi různými typy automobilů lišit. Nyní se podíváme, jak můžeme vytvořit objektově orientovaný program s tímto konceptem.
Začneme vytvořením třídy `Car`, kterou budou rozšiřovat další třídy představující různé typy automobilů.
abstract class Car { void start() { // implementace System.out.println("runs car"); } void stop() { // implementace System.out.println("engine stops"); } void reverse() { // implementace System.out.println("reverse mode enabled"); } abstract void selfDrive(); }
Metody jako `start()`, `stop()` a `reverse()` jsou běžné pro všechny automobily a jejich implementace je tedy definována přímo v třídě `Car`. Ovšem, implementace metody automatického řízení `selfDrive()` se může lišit pro různé typy automobilů. Proto ji definujeme jako abstraktní metodu, kterou následně implementujeme odlišně v podtřídách různých typů aut.
class CarTypeA extends Car { @Override void start() { super.start(); } @Override void stop() { super.stop(); } @Override void reverse() { super.reverse(); } void selfDrive() { // vlastní implementace System.out.println("Type A self driving mode enabled"); } }
class CarTypeB extends Car { // ...všechny podobné metody void selfDrive() { // vlastní implementace // jiná implementace než CarTypeB System.out.println("Type B self driving mode enabled"); } }
Důležité je si uvědomit, že pokud podtřída neimplementuje všechny abstraktní metody definované v abstraktní třídě, musí být sama deklarována jako abstraktní třída.
Rozhraní
Rozhraní je mechanismus, který definuje sadu metod, které musí třída implementovat. Například, pokud se vrátíme k příkladu s automobily, každý automobil má základní funkce jako startování, pohyb a zastavení. Tyto funkce jsou společné pro všechny vozy.
Pokud tedy implementujeme rozhraní `Car` ve třídě, musíme implementovat všechny tyto metody, aby automobil fungoval správně a bezpečně.
Podobně jako u abstraktních tříd, ani u rozhraní nemůžeme vytvářet instance, respektive objekty. Rozhraní lze chápat jako plně abstraktní třídu, protože obsahuje pouze abstraktní metody, tedy metody bez implementačního těla.
Rozhraní lze vytvořit pomocí klíčového slova `interface`.
interface CAR { void start(); void stop(); void move(); }
Rozhraní implementujeme pomocí klíčového slova `implements` při definování třídy.
class CarTypeB implements CAR { public void start() { System.out.println("started"); } public void stop() { System.out.println("stopped"); } public void move() { System.out.println("running"); } }
Podobnost
Zákaz vytváření instancí, tedy objektů, je jedním ze společných rysů abstraktních tříd a rozhraní.
Rozdíly
Abstraktní třída | Rozhraní | |
Dědičnost a implementace | Třída může dědit pouze z jedné abstraktní třídy. | Třída může implementovat více rozhraní. |
Typy proměnných | Může obsahovat proměnné finální, nefinální, statické a nestatické. | Může obsahovat pouze statické a finální proměnné. |
Typy metod | Může obsahovat abstraktní i neabstraktní metody. | Může obsahovat pouze abstraktní metody, s výjimkou statických metod. |
Modifikátory přístupu | Abstraktní třída může mít modifikátory přístupu. | Signatury metod v rozhraní jsou implicitně veřejné. Rozhraní nemá modifikátor přístupu. |
Konstruktory a destruktory | Může deklarovat konstruktory a destruktory. | Nemůže deklarovat konstruktory ani destruktory. |
Rychlost | Rychlá | Pomalejší |
Rozdíly mezi abstraktní třídou a rozhraním.
Kdy použít abstraktní třídu a rozhraní?
Abstraktní třídy se hodí v situacích, kdy:
- Je potřeba sdílet společné metody a atributy mezi více třídami.
- Je nutné deklarovat nestatické a nefinální atributy, které se dají měnit podle stavu objektu, se kterým jsou svázány.
Rozhraní se hodí v případech, kdy:
- Chceme definovat chování třídy, která rozhraní implementuje, aniž bychom se starali o detaily implementace.
- Je důležité zajistit, že třída implementuje všechny definované metody, aby správně fungovala.
Závěrečná slova
Rozhraní se primárně používají pro tvorbu API, neboť umožňují definovat strukturu implementace funkcí, bez nutnosti řešit konkrétní implementaci.
Abstraktní třídy se obvykle používají pro sdílení společných abstraktních a neabstraktních metod mezi třídami, které z nich dědí, což vede k lepšímu znovupoužití kódu.
Chcete-li se dozvědět více o Javě, podívejte se na dostupné online kurzy. Chystáte se na pohovor zaměřený na Javu? Zde je několik otázek k pohovoru zaměřených na objektově orientované programování.