autor: Ivan Kupka

Verzia 1

home uvod K1 K2 K3 K4 K5 K6 K7 K8 K9 K10 K11 K12 K13 K14

 

Java 7

 

 Rozhrania

 

Cieľ kapitoly: ukázať, ako sa pomocou rozhraní zabezpečí v fungovanie polymorfizmu, aj keď v Jave nemožno dediť od dvoch tried naraz.

 

 

Rozhranie

  Rozhranie sa podobá na abstraktnú triedu. Podobne ako ona definuje súbor metód.  Na rozdiel od abstraktnej triedy však rozhranie žiadnu metódu neimplementuje.  V deklarácii rozhrania sú iba hlavičky metódy. Tu je príklad konkrétneho rozhrania:

Kód P7.1

public interface Starozitnost {

         

   void vyrabamStarozitnost();

 

   void predavamStarozitnost();

         

}

 

Implementácia rozhraní triedou

  Trieda môže implementovať viacero rozhraní. Nevadí pritom, ak už je potomkom nejakej inej triedy.  Rozhrania používame, ak chceme rôzne triedy vybaviť tým istým typom metód. A pritom nemôžeme, alebo nechceme, (alebo nepotrebujeme ) skonštruovať ich spoločného predka.

  Konkrétny príklad:  Na Knihu sa niekedy môžeme dívať ako na Starožitnosť, inokedy ako na Odpad. A stále by sme ju pritom chceli vnímať ako potomka triedy tovar. Môžeme to zariadiť takto:

 

Kód P7.2

public interface Odpad {

         

           void zlikviduj();

}

 

 

Kód P7.3

public class Kniha extends Tovar implements Starozitnost,Odpad{

         

          String autor;

          String titul;

         

          public Kniha(String pisatel, String nazov, int cost){

                    // volanie konstruktora triedy Tovar:

                    super(cost);

                    System.out.println("Hlasi sa konstruktor triedy Kniha.");

              autor = pisatel;

            titul = nazov;      

          }

         

          public void vyrabamStarozitnost(){

            System.out.println("Na knihe " + this + " falsujem venovanie a podpis autora.");

            System.out.println("Robim stranky zazltnutymi. Jemne smirglujem obal. ");

                   

          }

         

          public void predavamStarozitnost(){

         

           System.out.println("\nPredavam knihu \"" + this + "\" ako starozitnost.");

            int povodnaCena = this.getCena();

            int novaCena = 10*povodnaCena;

           System.out.println("Stala " + povodnaCena +

                                       " Sk predavam ju za " + novaCena + " euro.\n");

                   

          }

          public void zlikviduj(){

                   

            System.out.println("Palim knihu " + this + " ako odpad.\n");  

          }

         

          public String toString(){

                    return titul;

          }

         

          public static void main(String[] args) {

         

            Kniha klasika = new Kniha("Andrej Sladkovic", "Marina", 101);

     System.out.println("Vytvoril som knihu s titulom \"" +klasika.titul +

                                              "\", cena je: " + klasika.getCena());

      klasika.vyrabamStarozitnost();                                         

      klasika.predavamStarozitnost();

                     

 

           Kniha memoare1 = new Kniha("Dracula", "Moj vecny smad", 99);

           System.out.println("Vytvoril som knihu s titulom \"" +memoare1.titul +

                                              "\", cena je: " + memoare1.getCena());

            memoare1.zlikviduj();                                

          }//EOMain

}//EOClass

 

Výpis:

 

Hlasi sa konstruktor triedy Tovar.

Hlasi sa konstruktor triedy Kniha.

Vytvoril som knihu s titulom "Marina", cena je: 101

Na knihe        Marina falsujem venovanie a podpis autora.

Robim stranky zazltnutymi. Jemne smirglujem obal.

 

Predavam knihu "Marina" ako starozitnost.

Stala 101 Sk predavam ju za 1010 euro.

 

Hlasi sa konstruktor triedy Tovar.

Hlasi sa konstruktor triedy Kniha.

Vytvoril som knihu s titulom "Moj vecny smad", cena je: 99

Palim knihu Moj vecny smad ako odpad.

 

 

 

 Metódy, deklarované v príkladoch rozhraní Starozitnost a Odpad boli zhodou okolností bez návratovej hodnoty a bez argumentov. V rozhraní však môžeme deklarovať ľubovoľný typ metódy. Ako sme už videli v príkladoch, trieda môže implementovať viacero rozhraní. V deklarácii triedy to signalizujeme kľúčovým slovom implements  menami príslušných rozhraní, oddelených čiarkami.

 

 

  Meno rozhrania ako referenčná premenná

 

 Implementujme rozhranie Odpad ešte do jednej triedy:

Kód P7.4

public class Vlas implements Odpad{

         

              static int kolkoNasiel = 0;

                       int kolkyVlas;

                   

                    public Vlas() {

                              kolkyVlas = ++kolkoNasiel;

                              System.out.println("Nasiel som vlas " + this);

                    }

                   

                    public void zlikviduj(){

                      System.out.println("Zahodil som do kosa vlas " + this);

                              }

                   

                    public String toString() {

                              return "cislo " + (new Integer(kolkyVlas)).toString();

                    }

                   

                   

}

 

  Metódu zlikviduj() sme samozrejme implementovali inak, ako v triede Kniha. Vlas sa ako odpad likviduje iným spôsobom ako kniha.

 

  Pri upratovaní by sme sa na objekty triedy Kniha a Vlas mohli dívať jednoducho ako na Odpad a tak (a iba tak) s nimi zaobchádzať:

 

Kód P7.5

public class Upratovanie{

         

          public static void main(String[] args){

                     Kniha cestopis = new Kniha("Halliburton","Cina",320);

                     Vlas prvy = new Vlas();

                     Vlas druhy = new Vlas();

                     

                     Odpad[] naVyhodenie = new Odpad[3];

                     naVyhodenie[0] = prvy;

         naVyhodenie[1] = cestopis;

          naVyhodenie[2] = druhy;

         

     System.out.println("Upratujem:");    

    

     for(int i = 0; i < 3; i++){

          naVyhodenie[i].zlikviduj();

     }

                   

          }//EOMain

}//EOClass

 

Výpis:

 

Hlasi sa konstruktor triedy Tovar.

Hlasi sa konstruktor triedy Kniha.

Nasiel som vlas cislo 1

Nasiel som vlas cislo 2

Upratujem:

Zahodil som do kosa vlas cislo 1

Palim knihu Cina ako odpad.

 

Zahodil som do kosa vlas cislo 2

 

 Pripomienka -varovanie

  Pomocou referenčnej premennej typu rozhranie môžeme pristupovať iba k tým metódam inštancie, ktoré sú v deklarácii rozhrania uvedené. K tomu, aby sme v konkrétnej triede, implementujúcej dané rozhranie, tieto metódy aj implementovali, nás prinúti prekladač. (Viď Cvičenie 7.1).

 

Keď dedíme triedu, dedíme aj jej rozhrania

  Trieda Kniha sa vyskytovala už v kóde P5.1B, kde ešte neimplementovala žiadne rozhrania. Čo sa stane, keď vezmeme teraz, po implementácii rozhraní Odpad a Starožitnosť triedou Kniha , s jej potomkom Detektivka?

Triedu Detektivka z kódu P5.3 pritom nezmeníme. Iba prepíšeme jej metódu main. Zistíme, či príslušné metódy daných dvoch rozhraní zdedí od triedy Kniha:

Kód P7.6

public class Detektivka extends Kniha {

         

          String menoDetektiva = "zatial sa nevie";

          String menoVraha     ="zatial sa nevie";

          int pocetMrtvol;

          boolean jeToKrvak;

         

          public Detektivka(String autor, String nazov, int cena, String detektiv, String vrah, int obete){

            super(autor,nazov,cena);        

            System.out.println("Tu konstruktor triedy Detektivka.");

            menoDetektiva = detektiv;

            menoVraha = vrah;

            pocetMrtvol = obete;

            if( obete > 10) jeToKrvak = true;

                   

          }

         

          public void dajInfo(){

                   

            System.out.println("\n Detektivka \"" + titul + "\", ktoru napisal renomovany autor " +

                                                 autor + "\n znova ukaze, ze detektiv " + menoDetektiva +

                                                  " odhali kazdeho vraha. \n Tentokrat rafinovaneho vraha " + pocetMrtvol + " obeti.");

        if(jeToKrvak){

          System.out.println("Osobam so slabsimi nervami odporucame citat v cakarni u lekara.");         

        }                                                 

          }

                   

         

          public static void main(String[] args){

                    Detektivka haluze = new Detektivka("Markiz Fero", "Smrt v krovi", 432, "Oresiansky","Jozef Zahradnik", 13);

                    //haluze.dajInfo();

           haluze.vyrabamStarozitnost();                                     

      haluze.predavamStarozitnost();

            haluze.zlikviduj();            

          }//EOMain

}//EOClass

 

Výpis:

Hlasi sa konstruktor triedy Tovar.

Hlasi sa konstruktor triedy Kniha.

Tu konstruktor triedy Detektivka.

Na knihe Smrt v krovi falsujem venovanie a podpis autora.

Robim stranky zazltnutymi. Jemne smirglujem obal.

 

Predavam knihu "Smrt v krovi" ako starozitnost.

Stala 432 Sk predavam ju za 4320 euro.

 

 

Palim knihu Smrt v krovi ako odpad.

 

 

Prekrytie metód

 

  Ak zdedíme rozhranie od materskej triedy, môžeme používať metódy rozhrania, ktoré sú v nej implementované. Takisto ale môžeme jednu alebo viacero z týchto metód v potomkovi prekryť.

 

Rozširovanie rozhraní

 Jedno rozhranie môže dediť iné rozhrania.  Na deklaráciu tohto javu sa použije kľúčové slovo extends. Napríklad takto:

public interface LeskABieda extends Starozitnost,Odpad 

}

  Triedy, implementujúce rozhranie LeskABieda musia implementovať všetky metódy, ktoré sú deklarované v zdedených rozhraniach Starozitnost a Odpad.

 

Cvičenia

Cv7.1

 V triede Vlas zakomentujte metódu zlikviduj() a sledujte reakciu prekladača.

Cv7.2

V kóde P7.6 implementujte metódu „zlikviduj()“ a tým pádom prekryte rovnomennú metódu z triedy Kniha.

Cv7.3

V niektorých učebniciach sa uvádza, že rozhranie na rozdiel od abstraktnej triedy nemôže deklarovať žiadne premenné. Je to pravda len čiastočne. V rozhraní premenné definovať môžeme, ale automaticky je im priradený status public, static a final. T. j. ide tu o konštanty, ktoré ďalej nemožno meniť.  Pridajte do rozhrania Starozitnost konštantu „koeficientPredrazenia“

  Túto konštantu potom použite v metóde „predavamStarozitnost()“  triedy Kniha namiesto pôvodného čísla 10.

 

Cv7.4

 Pokračujte v práci s kódmi z Cv7.3.  Pokúste sa koeficientPredrazenia nejakým spôsobom zmeniť: Napríklad pridať do rozhrania deklaráciu metódy  public void setKoeficient(int novaHodnota); a vhodne túto metódu v triede Kniha implementovať.

 

Cv7.5

a)    Vytvorte rozhranie LeskABieda, ktoré zdedí rozhrania Starozitnost a Odpad. Prepíšte hlavičku triedy Kniha tak, aby implementovala iba toto rozhranie. Spustite metódu-program Kniha.main().

b)    Do rozhrania LeskABieda pridajte metódu “propaguj()” , spustite preklad kódu Kniha. Dodefinujte do triedy kniha to čo je treba, aby bol znovu funkčný.

 

Riešenia:

Cv7.3

public interface Starozitnost {

  

   int koeficientPredrazenia = 20;          // toto je novy pridany riadok

   void vyrabamStarozitnost();

 

   void predavamStarozitnost();

            

           

}

 

a v metóde „predavamStarozitnost()“  nahraďte riadok

  int novaCena = 10*povodnaCena;

riadkom

  int novaCena = Starozitnost.koeficientPredrazenia*povodnaCena;

 

Cv7.4

V triede Kniha by sme mohli napísať:

public void setKoeficient(int novaHodnota){

   Starozitnost.koeficientPredrazenia = novaHodnota;

 

}

Pri ladení však prekladač odmietne kód preložiť, s odôvodnením, že finálnu hodnotu zmeniť nemožno.

 

 

home uvod K1 K2 K3 K4 K5 K6 K7 K8 K9 K10 K11 K12 K13 K14

Vaše komentáre: kupka@fmph.uniba.sk