Mozno ste uz presli kapitolou, kde sme nastavovali farbu obdlznika. Teraz je vhodny cas na to, aby sme sa pozreli na hlavny pilier Javy a objektovo-orientovaneho programovania, na triedy. V nasom priklade s farbou obdlznika sme definovali farbu ako instanciu triedy. Napriek tomu, ze asi vsetci viete, co je to instancia a co trieda, je dobre si upresnit, co je co.
Trieda je udajovy typ definovany uzivatelom. Reprezentuje skupinu objektov, ktore maju spolocne vlastnosti. Pri vzniku triedy sa nealokuje pamet (az na cleny static). Trieda vyzera napriklad takto:Myslim, ze kazdy, kto uz ma skusenosti s C++, bez problemov pochopil predchadzajuci programovy segment.public class Studenti { long Cislo; public void SetCislo(long _cislo) { Cislo=_cislo; } public long GetCislo() { return Cislo; } }
V jazyku Java ma kazda metoda urcene aj pristupove prava presne ako v C++, ale tieto prava je potrebne uviest pred kazdym datovym typom a metodou, ak si nezelame, aby neslo o pristup public. Z tohto dovodu su pristupove prava uvedene pred kazdou metodou z predchadzajuceho prikladu.
Instancia triedy je nieco ako premenna triedy. Na rozdiel od triedy ma alokovanu pamet. Niekedy instanciu triedy volame aj objekt. Pre nas budu tieto dva terminy uplne rovnocenne.
Clen triedy. Tento pojem som si zaviedol sam. Oznacuje datove cleny a metody triedy.
Telom triedy budem nazyvat nasledujucu cast programu:class MenoTriedy { // telo triedy }
Triedy v Jave
V najjednoduchsej forme vyzera trieda nasledovne:Jazyk Java trochu meni vzdialenost medzi deklaraciou a definiciou. Kym v jazyku C++ sme deklarovali triedy v hlavickovom subore, *.h, a jej definicia bola v *.cpp subore, v jazyku Java je to trochu inak.class MenoTriedy { // ... datove cleny ... // metody, ktore pracuju nad datovymi clenmi triedy }
Definicie aj deklaracie clenov triedy su obsiahnute v tej istej triede (= v tom istom subore). Nie je tu moznost definovat metody triedy niekde mimo tela triedy.
Konstruktor
Je to metoda, ktoru ma kazda trieda. Od ostatnych metod sa lisi tym, ze ma take iste meno ako je meno triedy. Vola sa pri vytvoreni instancie triedy. V pripade, ze nevytvorime konstruktor my, bude vytvoreny implicitny konstruktor interpreterom jazyka. Takyto konstruktor je velmi primitivny a vacsinou nesplna nase poziadavky, preto je potrebne vytvorit iny, ktory by dokazal spracovat, napriklad, vstupne (inicializacne) argumenty. V programatorskom svete to potom vyzera takto:Trieda Bod2D predstavuje bod v dvojrozmernom priestore. Instanciu takejto triedy vytvorime nasledujucim sposobom:class Bod2d { int x, y; // datove cleny Bod2D(int x0, int y0) { x=x0; y=y0; } }pomocou new alokujeme instanciu triedy Bod2D. new nevracia ukazovatel na objekt! V Jave neexistuje nic ako ukazovatel. Je dolezite poznamenat, ze pri nasledujucom priklade sa nealokuje pamet (na rozdiel od C++), iba sa povie, o aky typ ide:Bod2D koncovyBod = new Bod2D(10,20);Bod2D zaciatocnyBod;
Destruktor
Vola sa ak objekt zanika. V pripade, ze nedefinujeme vlastny destruktor, je interpreterom generovany implicitny. Destruktor je metoda s rezervovanym menom finalize. Trieda, ktora ho obsahuje vyzera ...Rezervovane slovicka public a protected su vysvetlene v nasledujucej casti.class TriedaA { public TriedaA() { // konstruktor } protected void finalize() { // destruktor } }
Private, Public, Protected, Friendly
Pred chvilou som spomenul pristupove metody k datovym clenom a metodam triedy. Existuju tri sposoby pristupu:
Pristupove prava je mozne vyrazne ovplyvnit rezervovanym slovickom friendly. Niekedy potrebujeme spristupnit metodu alebo datovy clen, ktory je zaradeny do skupiny private (alebo protected). Mohli by sme ho zmenit na public, ale to nie je vhodne, pretoze nechceme, aby bol pristupny aj pre ine triedy. My jednoducho trvame na svojom. Potrebujeme public pristup len pre jednu triedu. Oznacenim niektorej metody ako friendly ziskame pristup k ostatnym privatnym clenom triedy.
- private - pomocou tohto rezervovaneho slovicka programator specifikuje, ze clen triedy moze byt referencovany len z triedy, kde je definovany.
- protected - k clenom triedy, ktorym predchadza toto slovicko, je mozne pristupovat len v triede, kde su definovane a z tried, ktore vznikly odvodenim od tychto tried (potomkovia).
- public - urcuje, ze k takymto clenom triedy maju pristup vsetky triedy.
Staticke datove cleny a metody
Vsetko funguje podobne ako v C++. Kazdy staticky datovy clen triedy predchadza rezervovane slovicko static. Napriklad:Staticke datove cleny by sme mohli nazvat aj ako premenne triedy, pretoze kazda staticka premenna je viazana k triede a nie k objektu! Cize staticka premenna vznika pri definovani triedy a nie pri vytvoreni instancie danej triedy. Znamena to, ze ak vytvorime niekolko objektov triedy, ktora obsahuje staticky datovy clen, potom vsetky tieto objekty zdielaju dany staticky clen ako spolocnu pamet, do ktorej mozu pristupovat pomocou metod.class TriedaA { static int pocet_instancii; public TriedaA() { pocet_instancii++ } static int get_pocet() { return pocet_instancii } }
Staticka metoda je metoda, ktorej predchadza klucove slovo static. Staticka metoda moze pristupovat len k statickym premennym!
Tieto vlastnosti sa daju vyuzit na predavanie informacii medzi objektami tej istej triedy (okrem ineho). Napriklad ak chceme kontrolovat pocet instancii danej triedy, tak jednoducho v konstruktore tejto triedy inkrementujeme staticku premennu, ktoru sme na to vyclenili, a pri destruktore ju dekrementujeme. Tymto sposobom ziskame prehlad o tom, kolko instancii danej triedy sa prave nachadza v pameti. V praxi to vyzera takto:class TriedaB { // datovy clen (staticky) static int pocet_instancii = 0; // konstruktor public TriedaB() { pocet_instancii++; } // destruktor protected void finalize() { pocet_instancii--; } // staticka metoda static int get_pocet() { return pocet_instancii; } }
Okrem konstruktorov, destruktorov a statickych metod existuju aj "obycajne" metody ake pozname z C++. Odporucam pozriet si kapitolu Slovicko final, kde najdete popis final tried a metod.
Dedicnost
Je to mechanizmus, ktory nam umozni rozsirit existujuce triedy o nove vlastnosti. Triedu, od ktorej odvadzame novu triedu volame superclass a triedu odvodenu subclass. Budem pouzivat tieto anglicke nazvy, pretoze bude ovela jednoduchsie porozumiet niektorym veciam. Graficky je mozne proces dedenia zobrazit sposobom:Ak chceme vytvorit triedu Budik a triedu Hodiny urobime to pomocou rezervovaneho slovicka extends (v preklade znamena rozsiruje).superclass+ | Hodiny+ +---subclass1 | +---Budik +---subclass2 | +---Digitalky +---subclass3 | +---KukuckoveHodinyKompletnejsi priklad implementacie najdete tu. Pred tym, ako prejdem k inym veciam, musim upozornit este na jednu vec. Mozno ste si uz vsimli nieco podobne ako nasledujuci priklad:class Budik extends Hodiny { // telo triedy Budik }Chcel som upozornit na riadok cislo 4 (vyznaceny hrubym pismom). Na tomto mieste je volana metoda zakladnej triedy, od ktorej sme odvodili triedu HelloWorld, cize trieda Applet. Slovo super je odvodene od superclass (rodic, predchodca). A to je asi tak vsetko. Podme na nieco nove.1: class HelloWorld extends Applet { 2: 3: public void init() { 4: super.init(); 5: } 6: 7: public void paint(Graphics g) { 8: g.drawString("HelloWorld",10,10); 9: } 10: 11: }
Abstraktna trieda
je trieda, ktora obsahuje aspon jednu abstraktnu metodu. Zakladnou vlastnostou takejto triedy je, ze nie je mozne vytvorit jej instancie. Mozno viac napovie kratka ukazka:Abstraktna trieda ma vyznam ako zakladna trieda - superclass. Nie je totiz ziaduce, aby sme vytvarali od nej instancie, ale sluzi k odvodeniu ostatnych tried, ktore maju podobne vlastnosti ako ich superclass. Ak chceme vytvorit instanciu od jej podtriedy, musime prepisat vsetky abstraktne metody.class AbstraktnaTrieda { // datove cleny triedy // metody, ktore nad nimi pracuju abstract void AbstraktnaMetoda() { // a jej definicia } }
Podobnu myslienku obsahuju aj (po slovensky povedane) rozhrania. Asi netusite, o co ide. Interfaces. No teraz je to uz jasne.
Interfaces (rozhrania)
Rozhrania su oznacene dvoma klucovymi slovami. Prvym je uz znamy public a druhym interface. Rozhranie zahrna metody, ktore nie su definovane (nemaju telo). Asi bude najlepsi priklad :-\Takyto interfejs mozeme implementovat az neskor, ked rozhodneme, aky suborovy system vyuziva nas program. Potom dochadza k implementacii.public interface FileSystem { public int OpenFile(String fname); public int CloseFile(int fdesriptor); }Pomocou klucoveho slova implements sme urcili, ze ideme implementovat interfejs FileSystem. Potom v triede FAT32, ktora presne popisuje suborovy system FAT32, konkretizujeme, co je obsahom metod OpenFile a CloseFile.class FAT32 implements FileSystem { public int OpenFile(String fname) { return Open(fname); } public int CloseFile(int fdescriptor) { return Close(fdescriptor); } }