Java - rozhrania

Z Kiwiki
Verzia z 20:13, 5. december 2010, ktorú vytvoril Juraj (diskusia | príspevky)
(rozdiel) ← Staršia verzia | Aktuálna úprava (rozdiel) | Novšia verzia → (rozdiel)
Skočit na navigaci Skočit na vyhledávání
Imbox draft.png
Toto je projekt, na ktorom sa ešte stále pracuje!!

Aj keď sú v tomto dokumente použiteľné informácie, ešte nie je dokončený. Svoje návrhy môžete vyjadriť v diskusii o tejto stránke.

Na rozdiel on niektorých programovacách jazykov (napr. C++), v Jave nie je dovolená viacnásobná dedičnosť. Avšak možnosť dedenia z viacerých tried je niekedy veľmi potrebná. Riešením tohoto problému je v Jave mechanizmus rozhraní. Rozhranie je taktiež trieda (aj keď špeciálna). Termín implementácia rozhrania pre triedu potomka znamená, že táto trieda "zdedí" triedu v ktorej definujeme rozhranie.

Definícia rozhrania

Rozhranie sa používa pre vytváranie generických, resp. všeobecných šablón, ktoré môžu byť použité v iných triedach (normálnych alebo abstraktných). V triede rozhrania sú len deklarácie metód, ktoré sú implicitne definované ako verejné (public) a abstraktné (abstract). Môžu obsahovať aj vlastnosti, ktoré sú implicitne verejné (public) a statické konštanty (static final). Definícia rozhrania začína kľúčovým slovom interface. Z rozhrania, podobne ako z abstraktnej triedy nemôže byť vytvorený objekt.

Mechanizmus dedenia je povolený aj pri rozhraniach. Znamená to že môžeme vytvoriť rozhranie, ktoré bude rozširovať iné rozhranie. Java nepodporuje viacnásobné dedenie, avšak je možné použiť viacnásobnú implementáciu rozhraní[1].

Známe rozhrania v Jave

Rozhranie Runnable

Rozhranie Runnable poskytuje prácu s vláknami (threads). Obsahuje jednu metódu:

   public void run()

Rozhranie definujúce udalosti

Pri programovaní vizuálnych aplikácií potebujeme zachytiť udalosti ako je napríklad kliknutie myšou, stlačenie klávesy atď. Tieto udalosti môžeme priradiť napríklad appletu, alebo nejakému komponentu na applete, resp. oknovej aplikácii. Príklady udalostí a ich spracovania v appletoch sú v časti Java applety - interakcia s používateľom. Vo všeobecnosti ale platí, že zachytávanie udalostí môžem pridávať aj komponentom aplikácie. Napríklad tlačidlu zadefinujem udalosti "po kliknutí" a textovému bloku môžem zadefinovať udalosť "po stlačení klávesu".

MouseListener

Rozhranie MouseListener definuje metódy, ktoré ošetrujú udalosti spôsobené akciami myši. Toto rozhranie obsahuje deklaráciu metód:

  • mouseClicked
  • mouseEntered
  • mouseExited
  • mousePressed
  • mouseReleased

MouseMotionListener

Rozhranie MouseMotionListenerdefinuje metódy, ktoré ošetrujú udalosti spôsobené pohybom myši. Toto rozhranie obsahuje deklaráciu metód:

  • mouseDragged
  • mouseMoved

KeyListener

Rozhranie KeyListenermetódy, ktoré ošetrujú udalosti spôsobené akciami klávesnice. Toto rozhranie obsahuje deklaráciu metód:

  • keyPressed
  • keyReleased
  • keyTyped

Java Collections Framework

Java Collections Framework je knižnica rozhraní pre prácu s dátovými štruktúrami ako sú množina, zoznam, pole a iné. Nasledujúce rozhrania umožňujú pracovať so zložitejšími dátovými štruktúrami rôznymi spôsobmi: ako s poľom, ako so zoznamom, ako s množinou...

Rozhrnie List<E>

Toto rozhranie definuje metódy pre prácu s dátovou štruktúrou zoznam (List). Vybrané metódy z tohto rozhrania:

  • boolean add(E o); Do zoznamu pridá objekt o (objekt o je univerzálneho typu - E)
  • void clear(); Zoznam sa vyprázdni.
  • boolean isEmpty(); Testuje, či je zoznam prázdny
  • int size(); Vráti veľkosť zoznamu
  • Object[] toArray(); Vráti zoznam ako pole objektov.

Rozhrnie Set<E>

Toto rozhranie definuje metódy pre prácu s dátovou štruktúrou množina (Set). Keďže toto aj predchádzajúce rozhranie je potomkom rozhrania Collection, obsahuje rovnaké metódy.


Použitie rozhrnia Set a jeho implementácie HashSet

import java.util.HashSet;
import java.util.Set;
import java.util.SortedSet;

public class testZOO {
    public static void main(String[] args) {

        Zviera c = new Cicavec();
        Zviera v = new Vtak();
        Zviera p = new Plaz();

        Set s=new HashSet<Zviera>();
        boolean prazdna=s.isEmpty();
        System.out.println("Mnozina je pradna:" +prazdna);
        s.add(c);
        s.add(v);
        s.add(p);

        System.out.println("pocet zvierat v mnozine: "+s.size());
        prazdna=s.isEmpty();
        System.out.println("Mnozina je pradna:" +prazdna);

    }
}

Výstup z programu:

Mnozina je pradna:true
pocet zvierat v mnozine: 3
Mnozina je pradna:false

Ukážkový príklad

Rohranie

Opäť si zoberme hierarchiu tried Zviera-Cicavec-Pes-Vtak-Plaz. Vytvorme rozhranie jeZive. Toto rozhranie bude definovať základné metódy týkajúce sa "života" zvieraťa.

public interface jeZive {
    public void jest(int n);
    public boolean zije();
}

Nasleduje ukážka mechanizmu dedenia v rozhraniach. Rozhranie jeZdrave bude rozširovať rozhranie jeZive o metódy vaha() a rozmnozovat().

public interface jeZdrave extends jeZive{
    public void rozmnozovat();
    public int vaha();
}

Implementácia rozhrania

Rozhranie jeZdrave budeme implementovať v triede Zviera:

public abstract class Zviera implements jeZdrave {

    public String nazov;
    public int vaha;

    public Zviera() {
        this("Zviera", 0);
    }

    public Zviera(String nazov, int vaha) {
        this.nazov = nazov;
        this.vaha = vaha;
    }

    public String toString() {
        return "Zviera: " + this.nazov + ", Vaha: " + this.vaha;
    }

    public abstract void pohniSa(int k);

    public int vaha() {  // implementácia metódy z rozhrania jeZdrave
        return this.vaha;
    }

    public boolean zije() {  // implementácia metódy z rozhrania jeZive
        if (this.vaha > 0) {
            return true;
        } else {
            return false;
        }
    }
}

Podľa predchádzajúceho textu by sme očakávali, že v triede Zviera je potrebné všetky metódy definované v rozhraní jeZdrave implementovať (teda definovať telá metód). Avšak, trieda Zviera je abstraktná a tak implementácia metód nie je potrebná.

V triede Zviera budeme implementovať len metódu zije (z rozhrania jeZive) a metódu vaha (z rozhrania jeZdrave). Metódy rozmnozovat() a jest() nebudeme v triede Zviera implementovať. Tieto metódy bude teda potrebné implementovať v triedach Cicavec, Vtak a Plaz.

Poznamenajme, že v triede Zviera je ešte abstraktná metóda pohniSa, ktorú treba v podtriedach taktiež implementovať.

public class Cicavec extends Zviera {

    public int dlzka_gravidity;
    public String typ_srsti;

    public Cicavec() {
        super("Cicavec", 1);
        this.dlzka_gravidity = 7;
        this.typ_srsti = "";
    }

    public Cicavec(String nazov, int vaha, int dlzka_gravidity, String typ_srsti) {
        super(nazov, vaha);
        this.dlzka_gravidity = dlzka_gravidity;
        this.typ_srsti = typ_srsti;
    }

    public void pohniSa(int k) {
        System.out.println("bežím " + k + " metrov");
    }

    public String toString() {
        String g = super.toString();
        return g + ", Gravidita: " + this.dlzka_gravidity + ", Srst: " + this.typ_srsti;
    }

    @Override  // implementácia metódy rozhrania jeZdrave
    public void rozmnozovat() {
        System.out.println("Cicavec sa rozmnožuje");
    }

    @Override  // implementácia metódy rozhrania jeZive
    public void jest(int n) {
        System.out.println("Plaz prehltol " + n + " cicavcov");
    }
}

Trieda Vtak:

public class Vtak extends Zviera {
    public float rozpatie_kridel;
    public int pocet_vajec;

    public Vtak()
    {
        super("Vtak",3);
        this.rozpatie_kridel = 0;
        this.pocet_vajec = 8;
    }

    public Vtak(String nazov, int vaha, float rozpatie_kridel, int pocet_vajec) {
        super(nazov,vaha);
        this.rozpatie_kridel = rozpatie_kridel;
        this.pocet_vajec = pocet_vajec;
    }
   
   public void spievaj(){
      System.out.println("Snažím sa spevať");
   }

    @Override  // implementácia abstaktnej metódy triedy Zviera
    public void pohniSa(int k) {
        System.out.println("letim "+k+" metrov");
    }

    @Override  // implementácia metódy rozhrania jeZdrave
    public void rozmnozovat() {
        System.out.println("Vtak sa rozmnožuje kladenim vajec");
    }

    @Override  // implementácia metódy rozhrania jeZive
    public void jest(int n) {
          System.out.println("Vtak vyzobal "+n+" kg zrna");
    }
}

A trieda Plaz:

public class Plaz extends Zviera {

    public float dlzka;
    public String typ;

    public Plaz(String nazov, int vaha, float dlzka, String typ) {
        super(nazov, vaha);
        this.dlzka = dlzka;
        this.typ = typ;
    }

    public Plaz() {
        super("Plaz", 2);
        this.dlzka = 10;
        this.typ = "";
    }

    public void pohniSa(int k) {
        System.out.println("plazím sa " + k + " metrov");
    }

    public String toString() {
        return "Plaz" + this.dlzka + " " + this.typ;
    }

    @Override  // implementácia metódy rozhrania jeZdrave
    public void rozmnozovat() {
        System.out.println("Plaz sa rozmnožuje");
    }

    @Override  // implementácia metódy rozhrania jeZive
    public void jest(int n) {
        System.out.println("Plaz prehltol " + n + " cicavcov");
    }
}

Testovanie vytvorených tried

Pre overenie správnosti napísaných tried si vytvorme triedu, kde si overíme funkčnosť našich rozhraní:

public class testZOO {
    public static void main(String[] args) {

        //Zviera z=new Zviera();
        Zviera c = new Cicavec();
        Zviera v = new Vtak();
        Zviera p = new Plaz();

        c.pohniSa(2);
        v.pohniSa(2);
        p.pohniSa(2);

        c.jest(2);
        v.jest(4);
        p.jest(4);

        c.rozmnozovat();
        v.rozmnozovat();
        p.rozmnozovat();
        
    }
}

Výstup z tohoto programu je nasledovný:

bežím 2 metrov
letim 2 metrov
plazím sa 2 metrov
Plaz prehltol 2 cicavcov
Vtak vyzobal 4 kg zrna
Plaz prehltol 4 cicavcov
Cicavec sa rozmnožuje
Vtak sa rozmnožuje kladenim vajec
Plaz sa rozmnožuje

Porovnanie abstraktných tried a rozhraní

Kedy použiť rozhranie a kedy abstraktnú triedu?

Použitie rozhrania
V rozhraní definujeme metódy, ktoré do istej miery spolu v určitej oblasti súvisia. Toto rozhranie môžeme použiť vo viacerých triedach, ktoré nemusia mať nič spoločné. Napríklad rozhranie jeZdrave môžeme implementovať v triede Zviera, ale aj v triede Rastlina.
Použitie abstraktnej metódy
Pri použití abstraktnej triedy sa predpokladá určitý vzťah medzi triedami (Zviera-Cicavec-Pes). Pre triedy Zviera a Rastlina vy sme museli vytvoriť nejakú abstraktnú triedu, ktorá by definovala spoločné vlastnosti zvieraťa aj rastliny.

Hlavné rozdiely medzi abstraktnou triedou a rozhraním sú opísané v nasledujúcej tabuľke[2]:

Porovnanie rozhrania a abstraktnej triedy
Vlastnosť Rozhranie Abstraktná trieda
Viacnásobná dedičnosť Trieda môže implementovať niekoľko rozhraní Trieda môže rozšíriť iba jednu abstraktnú triedu
implicitná implementácia Rozhranie nemôže obsahovať kód implementácie Abstraktná trieda môže obsahovať určitú časť implementácie.
Konštanty Môže obsahovať len statické konštanty (static final). Použitie konštánt v rozhraniach avšak nie je bežné. Môže obsahovať tak ako konštanty aj vlastnosti (inštančné premenné)
Použitie v triedach tretích strán Implementácia rozhrania môže byť jednoducho pridaná do tried tretích strán Triedy tretích strán musia byť prepísané tak, aby boli potomkami len jednej abstraktnej triedy.
Rýchlosť Pomalá, resp. pomalšia. Pri spúšťaní potrebuje nájsť korešpondujúcu metódu v aktuálnej triedy. Rýchla, resp. rýchlejšia.
Pridanie funkcionality Ak sa do rozhrania pridá nová metóda, táto sa musí implementovať v každej triede s týmto rozhraním. Ak sa do abstraktnej triedy pridá nová metóda, tejto metóde môžeme definovať telo v abstraktnej triede (triedy potomkov budú bez zmeny) alebo sa bude musieť metóda implementovať v triede potomka.

Zdroje a odkazy