Warning
This page is located in archive. Go to the latest version of this course pages. Go the latest version of this page.

Rozhraní (interface)

Rozhraní je velice podobné abstraktním třídám. Jedná se o “něco jako třídu”, zkrátka rozhraní, které definuje metody, ale nikoliv jejich implementace. To znamená, že v rozhraní jsou vždy všechny metody abstraktní, a proto se také nemusí psát (a ani nepíše) klíčové slovo abstract. Příklad definice rozhraní:

public interface Iface {
    public void foo();
}

Rozhaní pak jednotlivé třídy implementují:

public class Impl implements Iface {
    public void foo() {
        System.out.println("foo");
    }
}

Třída, která implementuje nějaké rozhraní, musí implementovat všechny metody rozhraní. Nicméně existuje výjimka z tohoto pravidla, a to abstraktní třídy. Pokud je třída abstraktní, tak nemusí implementovat všechny metody (nebo žádnou) ze svých rozhraní. Nebo obráceně - pokud necheme implementovat všechny metody z rozhraní, musíme třídu označit jako abstraktní. Příklad:

public abstract class AbstractImpl implements Iface {
 
}

Rozhraní navíc fungují jako typ. Tzn. je možné (a velmi často vhodné) volání

Iface x = new Impl();

Vám známý List je také rozhraní, nikoliv třída. Jednotlivé implementace (ArrayList, LinkedList) toto rozhraní implementují.

Rozhraní mezi sebou také mohou mít hierarchii, tzn. jedno rozhraní může být potomkem (dědit od) rozhraní jiného. Příkladem budiž opět známá rozhraní List a Collection, kde List je potomkem Collection. Chová se to pak podobně jako u tříd, tzn. potomek má metody jak své tak metody předka, ale jelikož u rozhraní nejsou žádné implementace, tak přepisování (overriding) zde postrádá smysl.

Proč rozhraní

Nabízí se otázka: proč máme v Javě dva podobné mechanismy, a to abstraktní třídy a rozhraní? Důvod je jednoduchý: v jazyce Java může třída dědit pouze od jedné třídy, ale může implementovat libovolný počet rozhraní.

Rozhraní se obecně využívají právě pro definici rozhraní. Tzn. v rozhraní popíši, jak chci, aby s objektem šlo manipulovat (jaké operace na něm budou existovat) a implementaci nechám na konkrétních třídách. Jelikož jsem udělal definici skrze rozhraní, konkrétní třídy stále mohou dědit od jiných tříd.

Krásný příklad je třída Thread a rozhraní Runnable. Jedná se o vlákna, ke kterým se dostaneme až za několik týdnů, ale o samotná vlákna tu nejde. Jde o to, že vlákno je možné vytvořit dvěma způsoby:

  1. Vytvořím potomka třídy Thread.
  2. Vytvořím třídu implementující Runnable a tu pak vložím jako argument do konstruktoru Thread.

První možnost je nejjednodušší, ale už si tím zavřu dveře k dědění od jiné třídy, takže nemůžu použít jinou funkcionalitu. Když ale implementuji rozhraní Runnable, tak jsem pořád schopen vlákno vytvořit, ale stále můžu dědit od jiné třídy.

courses/b0b36pjv/tutorials/04/interfaces.txt · Last modified: 2021/03/03 11:11 by seredlad