A Jáva programozási nyelv rejtelmei (II.)

Objektumorientált programozás Jáva módra

Manapság az objektumorientáltság az egyik legfelkapottabb programozási paradigma (alapelv) -- természetesen a Jáva is követi a divatot. Bár szülôje a C++ volt, a Jávában sokkal tisztábban érvényesülnek az objektumorientált programozás elvei, talán azért, mert nem kényszerül arra, hogy még a C nyelvbôl származó programozási elveket, szerkezeteket koloncként hordozza magával.

Az objektumorientáltság még eléggé új elv ahhoz, hogy a teoretikusok felhevült hitvitákban próbálják meghatározni lényeges vonásait. A teljesség igénye nélkül az egyik széles körben használt definíciót ismertetjük, természetesen azt, amelyik illik a Jávára:

· Egy objektumorientált program együttmûködô objektumok (object) összessége.

· A program alapépítôkövei az objektumok. Ezek olyan, a környezetüktôl jól elkülöníthetô, viszonylag független összetevôk, amelyeknek saját viselkedésük, mûködésük és -- lehetôleg rejtett, belsô -- állapotuk van. Egy objektumra a környezetében lévô egyéb objektumok hatnak, és ennek nyomán saját állapotuk megváltozhat.

· Minden objektum valamilyen osztályba (class) tartozik. Ezek megfelelnek az absztrakt adattípusoknak, minden objektum valamely típus példánya, egyede (instance). Az osztályok definiálják az egy-egy objektum állapotát leíró adatszerkezetet és a rajtuk végezhetô mûveleteket, az úgynevezett módszereket (method). Az egyes egyedek csak az állapotukat meghatározó adatszerkezet tényleges értékeiben különböznek egymástól, a módszerekkel definiált viselkedésük közös.

· Az egyes osztályokat az öröklôdés hierarchiába rendezi. Az öröklôdés segítségével egy osztály felhasználhatja a hierarchiában felette álló osztályokban definiált állapotot (adatszerkezeteket) és viselkedést (módszereket). Így a redundáns elemeket elég egyszer, a hierarchia megfelelô szintjén definiálni.

Általában csak az elsô három követelménynek eleget tevô programozási nyelvet, technológiát objektumalapúnak (object based), míg a negyedikkel kiegészülôket objektumorientáltnak (object-oriented) hívják. Az elsô három építôelem már korábbi programozási nyelvekben is megjelent, ezeket absztrakt adattípusoknak nevezték. Kezdetben mi is ezzel foglalkozunk.

Absztrakt adattípusok létrehozása

A Jáva nyelvben csaknem minden objektum. Elôzôleg már szó volt arról, hogy egy programban az importutasításokon kívül valamennyi utasítás osztályok belsejében szerepelhet csupán, nincsenek globális változók, globális eljárások. A nyelv ugyan tartalmaz néhány egyszerû adattípust, de ezeken felül minden egyéb adatszerkezet vagy valamilyen osztályba tartozó objektum vagy tömb, amely, mint azt hamarosan látni fogjuk, ugyancsak speciális osztály. Mellesleg a nyelv tartalmaz a beépített típusokat becsomagoló osztályokat (wraper class) is: Boolean, Character, Double, Float, Integer.

Objektumok

Az objektumok olyan programösszetevôk, amelyek szoros egységbe foglalják az állapotukat leíró belsô adatszerkezetüket és a rajtuk értelmezhetô mûveleteket. Ebben az értelemben az egyes objektumok nagyon hasonlítanak egy adott típusba tartozó értékekhez. Egy int típusú érték is elrejti elôlünk belsô reprezentációját, és csak az elôre definiált mûveletek végezhetôk rajta. A Jávában minden egyes objektumnak meghatározott típusa kell hogy legyen, azaz valamelyik osztályba kell tartoznia. Az objektumokra változókon keresztül hivatkozhatunk, pl. a

Person somebody;

azt jelenti, hogy a somebody név mindig egy Person típusú objektumra hivatkozik.

A C++ nyelvvel ellentétben a fenti deklaráció nem jelenti egy új objektum létrejöttét, a változó egyelôre nem hivatkozik semmire, azaz "értéke" nulla.

A Person somebody = new Person ("Kovacs", "Istvan", "15502290234");

nemcsak definiál egy új változót, de a new paranccsal létre is hoz egy új objektumot, amelyre a változó hivatkozik.

Nagyon fontos megértenünk azt, hogy a Jávában minden változó hivatkozást tartalmaz csupán. Ezt szem elôtt tartva érthetô, hogy az értékadás (=) operátor nem készít másolatot, a bal oldali változó ugyanarra az objektumra hivatkozik majd, mint a jobb oldal. Ha valakinek mégis másolatra van szüksége, többnyire használhatja a csaknem minden osztályban megtalálható clone módszert. Hasonlóképpen az egyenlôség vizsgálatának C-bôl ismert operátora (==) is a referenciák egyenlôségét ellenôrzi, az objektumok strukturális ellenôrzésére az equal módszer való, már amennyiben létezik ilyen.

Ha már minden objektumra amúgy is csak referenciákon keresztül hivatkozhatunk -- természetesen a hivatkozás feloldásának mûveletét (dereference) nem kell külön kiírnunk --, nem is tûnik túl meglepônek, hogy a Jáva nem tartalmaz külön mutatótípust. Ez nagyon sok programozási hibától, biztonsági problémától megkímél bennünket. A referenciák ellenben szentek és sérthetetlenek, semmiféle mûvelet, konverzió nem végezhetô rajtuk.

Az egyes referenciák által hivatkozott objektum típusát az instanceof logikai értéket adó operátorral kérdezhetjük le, például:

if (x instanceof Person) then system.out.println("x egy személy!");

Azt már láttuk, hogy új objektumokat a new utasítással lehet létrehozni, megszüntetni, törölni viszont nem kell. A Jáva virtuális gép, amely a programokat futtatja, tartalmaz egy szemétgyûjtô (garbage collection, gc) -- jelenleg az ún. mark-and-sweep típusú -- algoritmust, amelyik rendszerint a háttérben, a CPU szabadidejében, a programmal aszinkron futva összegyûjti a már nem hivatkozott objektumokat, és azok tárterületét felszabadítja, hogy a new újra felhasználhassa majd.

A szemétgyûjtés teljesen rejtetten, automatikusan történik, a programozóknak általában nem is kell ezzel törôdniük.

Ha már vannak objektumaink, nézzük meg, hogyan tudunk hatni rájuk. Az egyes objektumok módszereit az

obj.method(parameter, parameter, ...)

szintaxissal hívhatjuk meg. Az objektumorientált terminológia ezt gyakran üzenetküldésnek (message passing) nevezi, pl. a

somebody.changePID("5502290234");

utasítás "megkéri" a somebody objektumot, hogy hajtsa végre -- saját magán -- a changePID mûveletet az "5502290234" paraméterrel. Az ilyen módszerhívások vezethetnek az objektum belsô állapotának megváltozásához is, de gyakran csak egy belsô változó értékének lekérdezése a cél.

Bár a tiszta objektumorientált elvek szerint egy objektum belsô állapotváltozóinak értékéhez csak módszerein keresztül lehetne hozzáférni, a Jáva -- a C++-hoz hasonlóan -- megengedi a programozónak, hogy bizonyos változókat közvetlenül is elérhetôvé tegyen. Pl. a

somebody.age = 46;

utasítás közvetlenül a példaszemélyünk életkorát változtathatja meg.

Osztályok definíciója

A Jáva programozók osztályokat a

class ClassName { ... ClassBody ... }

programszerkezettel definiálhatnak, ahol a ClassName az újonnan definiált osztály neve lesz, az objektumok belsô állapotát és viselkedését pedig a kapcsos zárójelek közötti programrészlet írja le. A class alapszó elôtt, illetve az osztály neve után opcionálisan állhatnak még különbözô módosítók, de ezekrôl majd késôbb.

Egyedváltozók

Az osztály törzsében szerepelnek azok a változó deklarációk, amelyek az egyes egyedek belsô adatszerkezetét valósítják meg. Ezeket gyakran egyedváltozóknak (instance variable, member variable) nevezzük, jelezve, hogy az osztály minden egyede saját készlettel rendelkezik ezekbôl a változókból. A változó deklarációk megfelelnek a C-ben megszokottaknak:

class Person

{

String name, surname, pid;

byte age;

Person mother, father;

A képzeletbeli Person típusunkba tartozó egyedek három szövegváltozóban tárolhatják a személy vezeték- és keresztnevét, személyi számát (ez persze lehetne akár egy long egész szám is), egy Byte-ban az életkorát és két Person típusú változóban az apját és anyját. Az utolsó két változó példa arra, hogy egy egyed belsô állapota hivatkozhat más, akár megegyezô típusú objektumokra is.

Módszerek

A típus által értelmezett mûveleteket a módszerek testesítik meg, ezek definiálása megegyezik a C függvényekével:

void changePID (String newPID) trows WrongPIDException

{

if (correctPID(newPID)) pid = newPID

else throw new WrongPIDException();

}

Mint látjuk, az egyes módszereknek lehet visszatérési értéke -- bár példánkban nincsen, ezt jelzi a kötelezô void --, illetve adott típusú és számú bemenô paramétere. A módszer nevét, visszatérési értékének és paramétereinek számát, típusát a módszer lenyomatának (signature) nevezzük.

A módszerek meghívásánál a lenyomatban definiált formális paraméterek aktuális értéket kapnak. A Jávában minden paraméter-átadás érték szerint történik, azaz a paraméter helyén szereplô értékrôl másolat készül, a módszer ezt a másolatot látja, használja. Természetesen a másolat módosulása nem érinti az eredeti értéket.

Kicsit becsapós a "mindig érték szerinti paraméter-átadás" szabálya. Amennyiben a paraméter nem valamelyik beépített, egyszerû típusba tartozik, úgy az átadásnál a referenciáról készül másolat, azaz a C++ fogalmai szerint ilyenkor referencia szerinti átadás történik. A visszatérési érték sem feltétlenül egy egyszerû típusba tartozó érték, hanem lehet objektum-referencia is.

Az osztály belsejében azonos névvel, de egyébként különbözô lenyomattal több módszert definiálhatunk (többes jelentés, overloading), ilyenkor a fordító a módszer hívásánál a paraméterek számából és típusából dönti el, hogy melyik módszert akarjuk meghívni. A módszer visszatérési értékének típusát a fordító nem veszi figyelembe.

A módszerek törzsében a korábban már megismert utasításokat írhatjuk. A kifejezésekben, az értékadások bal oldalán használhatjuk az eljárás paramétereit, lokális változóit, de egyedváltozóinak értékét is. Ha a saját objektumra akarunk hivatkozni, akkor alkalmazzuk a this szimbólumot. Például a pid= newPID azonos a this.pid = newPID utasítással, de ezt a hosszabb formát csak a névütközések elkerülése végett kell alkalmaznunk.

Konstruktor

Az osztályban definiált módszerek közül kitûnnek az ún. konstruktorok (constructor), melyek szerepe az objektumok létrehozása, belsô állapotuk kezdeti értékének beállítása. Minden konstruktor neve megegyezik az osztálya nevével, visszatérési értéke pedig nincs. Természetesen a konstruktor is lehet többes jelentésû módszer:

Person () { /* ures */ };

Person (String name, String surname, String PID)

{ Person(); // az ures konstruktor egyelore nem csinal semmit

this.name = name; this.surname = surname; this.PID = PID;

...

};

A new utasítás kiadása hívja meg a konstruktorokat, amelyek közül a new-nál megadott paraméterek száma és típusa szerint választunk.

Kitüntetett szerep illeti meg a paraméter nélküli, ún. alap- (default) konstruktort; ha mi nem definiáltunk ilyet, a Jáva fordító automatikusan készít egyet az osztályhoz. Az így generált konstruktor a helyfoglaláson kívül mást nem csinál.

A szemétgyûjtés miatt a C++-ból ismert destruktorok itt nem léteznek, viszont ha egy objektum végleges megszüntetése elôtt valamilyen rendrakó tevékenység végrehajtására lenne szükség, akkor ezt írjuk egy void finalize() lenyomatú módszer törzsébe, a Jáva virtuális gép biztosan végrehajtja, mielôtt az objektum területét a szemétgyûjtô felszabadítaná -- azonban az aszinkron szemétgyûjtés miatt azt soha nem tudhatjuk biztosan, hogy ez mikor következik be.

Osztályváltozók és

-módszerek

Míg az egyedváltozókból minden példány saját készlettel rendelkezik, addig az ún. osztály- vagy statikus (static) változókból osztályonként csak egy van. Természetesen, mivel ezek nem egy példányhoz tartoznak, a hozzáféréshez sincs szükség egy konkrét objektumra, az osztály nevével is hivatkozhatunk rájuk.

A statikus változókat alkalmazó módszerek a statikus vagy osztálymódszerek.

Egészítsük ki a személy példánkat úgy, hogy minden új személy kapjon egy egyedi sorszámot:

class Person

{

...

int index; // egyedi sorszam

static int counter; // letrejott szemelyek szamlaloja

static { counter = 0; } // statikus valtozo kezdeti erteke

Person () { index = counter++; }

// a konstruktorban hasznaljuk fel a szamlalot

static int howManyPersons () { return counter; )

...

}

Tömbök

A Jáva nyelv tömbjei is objektumok, ha kissé speciálisak is. Deklarálásuk nemcsak a C-szerû szintaxissal megengedett, de végre tehetjük a szögletes zárójeleket a "logikus helyére is", azaz a következô két deklaráció ekvivalens:

int a[] = new int[10];

int[] a = new int[10];

Mint a többi objektumnál, a név ennél is csak egy referencia, a tömb deklarációja után azt a new paranccsal létre is kell hozni. Az indexelés mûvelete azonos a C-ben megismerttel, itt is 0 a legkisebb index. Lényeges különbség viszont, hogy a virtuális gép ellenôrzi, hogy ne nyúljunk túl a tömb határán; kivétel keletkezik, ha mégis megteszszük. Minden tömbobjektumnak van egy length nevû egyedváltozója, amely a tömb aktuális méretét adja vissza. Ez azért is fontos, mert a program futása során ugyanaz a tömbváltozó más és más méretû tömbökre mutathat.

Természetesen nemcsak a beépített, egyszerû típusokból képezhetünk tömböket, hanem tetszôleges típusból, beleértve egyéb tömböket is. A Jáva többdimenziós tömbjei is mint tömbök tömbje jönnek létre. Például:

int a[][] = new int[10][3];

system.out.println(a.length); // 10-et ír ki

system.out.println(a[0].length); // 3-at ír ki

Szövegek

A Jávában a szövegek (String) is teljes rangú objektumok. A szövegek gyakori módosításának hatékonyabb elvégzésére használhatjuk a StringBuffer osztályt is. Részletes magyarázkodás helyett álljon itt egy példa, egy olyan módszer, amelyik megfordít egy szöveget:

String reverse (String source)

{

int i, len = source.length();

StringBuffer dest = new StringBuffer(len);

for (i = (len - 1); i >= 0; i--) dest.append(source.charAt(i));

return dest.toString();

}

Pakkok

Összetartozó osztályokat a pakk (package) révén a programozók egyetlen fordítási egységgé foghatnak össze. Ezzel osztálykönyvtárakat építhetünk, és segítségünkre van a láthatóság szabályozásánál is. A pakkot, amennyiben használjuk egyáltalán, a forrás elsô nem megjegyzés sorában kell megneveznünk, pl.:

package mmt.networking.snmp

Programozási konvenciók szerint a pakkoknak általában több komponensû, ponttal elválasztott nevet adunk, a fordító a névnek megfelelô könyvtár-hierarchiába helyezi el a lefordított osztályokat. Létezik egy név nélküli pakk arra az esetre, ha nem adtuk meg a package utasítást.

Az így létrehozott pakkokból lehet a múltkor megismert import utasítással egy vagy több osztályt átvenni, használni. A Jáva nyelvi környezet jelenleg a következô pakkokat tartalmazza:

java.applet  programkák környezete 
java.awt  ablakozó rendszer (Abstract Windowing Toolkit) 
java.awt.imagejava.awt.peer  segédosztályok az AWT-hez 
java.io  be- és kivitel 
java.lang  nyelvi szinten definiált osztályok 
java.net  hálózatkezelés 
java.util  segédosztályok 

Láthatósági viszonyok

A programozók megadhatják, hogy az általuk definiált egyes osztályok, illetve azok változói, módszerei milyen körben alkalmazhatók. Erre a célra az ún. hozzáférést specifikáló (access specifier) módosítók használatosak.

Egyelôre -- amíg az öröklôdésrôl nem beszéltünk -- három ilyen specifikáló lehet: nyilvános (public), magán (private), "baráti" (friendly). Ez utóbbi az alapértelmezés, ha nem adjuk meg a hozzáférés módját, akkor ez mindig baráti.

Osztályokra csak a nyilvános vagy a baráti hozzáférés vonatkozhat: nyilvános osztályokat bárhol használhatunk programunkban, bármelyik pakkunkba importálhatunk. Baráti osztályokat csupán az adott pakkon belül lehet használni.

Egyed-, illetve osztályváltozókra, módszerekre a nyilvános és baráti hozzáférés a fentivel azonos jelentésû, ezen túlmenôen a magánváltozók, módszerek csak az adott osztályon belül láthatók.

Öröklôdés és következményei

Az objektumorientáltság igazi csattanója az öröklôdés. Ez teszi lehetôvé, hogy a korábbi programozási módszereknél jóval könnyebben felhasználhassunk már megírt programrészeket, ezt gyakran szoftver IC-knek reklámozzák. Bár egyelôre az objektumorientált paradigma nem váltotta be minden ígéretét, de tagadhatatlan, hogy nemcsak divatos, de sikeres is.

Osztályok leszármaztatása

Ha egy új osztályt már valamelyik meglévô alapján akarunk definiálni, azt az osztály fejében a következô szerkezettel kell jelezni:

class Child extends Parent { /* Child törzse */ }

Az ily módon megadott, ún. leszármazott osztály (Child) örökli szülôje (Parent) tulajdonságait, azaz a belsô állapotát leíró adatszerkezetét és a viselkedést megvalósító módszereit. Természetesen az osztály törzsében ezt tovább bôvítheti, viselkedését módosíthatja, ezt sugallja az extends (kiterjeszt) kifejezés a definíciónál.

A Jáva a C++-szal ellentétben csak az ún. egyszeres öröklôdést engedélyezi, azaz minden osztálynak egyetlen közvetlen szülôje lehet. Tulajdonképpen nemcsak lehet, de van is: a nyelv definiál egy beépített Object nevû osztályt, amennyiben az új osztály definíciójában máshogy nem rendelkezünk, automatikusan "extends Object" értendô, vagyis valamennyi osztály közvetlenül vagy közvetve, de örökli az Object-ben definiáltakat. Az így örökölt módszerek például az egyes objektumok másolásával (clone), összehasonlításával (equals), megnevezésével (toString), illetve osztálya megkülönböztetésével (getClass) vagy a többszálú futtatással (pl. wait, notify) kapcsolatosak.

Szükség esetén a meglévô osztályainkból való leszármaztatást megtilthatjuk oly módon, hogy azt "final class"-ként definiáljuk. Ezt akkor alkalmazzuk, ha nem akarjuk, hogy egy mások által leszármaztatott osztály nem kívánt módon módosítson az osztályunkban definiált viselkedésen.

Láthatóság

Az absztrakt adattípusoknál megismert, hozzáférést szabályozó módosítók -- public, private és a soha ki nem írt friendly -- a protected (védett) alapszóval bôvültek. A védettnek definiált változók és módszerek csak az osztályban, annak valamelyik leszármazottjában vagy a pakkban láthatók, míg a privát védett (private protected) változók az elôzôhöz képest általában a pakkokban sem látszanak (ez a C++-ban járatosak számára az ottani protected láthatóság megfelelôje).

Mi öröklôdik és mi nem?

Az öröklés során az új osztály örökli szülôje összes egyedváltozóját, még akkor is, ha azok egy private deklaráció miatt közvetlenül nem láthatók. Ekkor is megvannak, és ha közvetlenül nem is, de a szülô nem magánmódszereinek segítségével akár módosíthatók is.

Alapvetôen a módszerekkel szintén hasonló a helyzet, egy leszármazott osztályban használható a szülô bármelyik nyilvános, védett vagy baráti módszere. Ám ebben az esetben nagyobb szabadságunk van: ha a leszármazottban a szülôben meglévô módszerrel azonos lenyomatú módszert definiálunk, az elfedi a szülôbeli jelentést, így megváltoztatva egy a szülôben definiált viselkedést.

Láttuk, hogy egy módszerben a saját egyedváltozókra a this referencia segítségével hivatkozhatunk, öröklôdés esetén a szülôbôl örökölt egyedváltozókra, módszerekre való hivatkozásnál a super referenciát használhatjuk.

Természetesen az új osztályban láthatók lehetnek a szülô osztályváltozói és az ezeket kezelô statikus módszerek is, ez azonban nem igazán öröklés, hanem inkább kölcsönös használat, minden statikus változóból továbbra is csak egy van.

Nem öröklôdnek a konstruktorok, valamennyi osztálynak meg kell írni a sajátjait. Ebbôl a fordító csak az alap -- paraméter nélküli -- konstruktort hajlandó automatikusan létrehozni, amely úgy mûködik, hogy miután a tárban -- a kazalon (heap) -- az egyed számára helyet foglalt, lehívja a szülô alapkonstruktorát, a super()-t. Egy leszármazottbeli konstruktor ezt az alap-szülôkonstruktort mindig automatikusan meghívja, hacsak a leszármazott konstruktorában valamely más paraméterezésû super(...) konstruktort -- saját konstruktorának elsô utasításaként -- meg nem hív.

Végezetül az öröklôdésben érdekes szerep jut az ún. absztrakt módszereknek, amelyeknek egy osztály csak a fejét (lenyomatát) definiálja, de a törzse helyét kihagyja.

Polimorfizmus

A polimorfizmus többalakúságot, többarcúságot jelent. Az objektumorientált nyelveknél ez valami olyasmire utal, hogy különbözô típusú objektumoknak lehet azonos lenyomatú módszere, és e módszerek közül az objektum aktuális típusának megfelelô módszer kerül meghívásra.

Ez persze csak akkor izgalmas, ha a program szövegébôl nem látszik konkrétan, hogy éppen milyen típusú elemmel van dolgunk. Egy szigorúan típusos nyelvnél, mint a Jáva, ez csak úgy lehetséges, ha bizonyos lazításokat vezetünk be, pl. megengedjük, hogy egy szülô típusú referencia aktuálisan hivatkozzék valamelyik leszármazott típusra is.

Definiáljunk mondjuk egy jól ismert vicc nyomán a példabeli Person osztályunkban egy absztrakt pressToothPaste nevû módszert a fogpaszta kinyomására a tubusból:

class Person { ... void pressToothPaste(); ... }

Származtassuk le a férfi és a nô osztályokat a személybôl, ezekben már konkrétan megadva, hogyan is szokták a férfiak és a nôk a fogkrémes tubust megnyomni:

class Man extends Person

{

void pressToothPaste() { /* ... tekerd fel az egyik végérôl kezdve ... */ };

class Woman extends Person

{

void pressToothPaste() { /* ... markold középen és nyomjad ... */ };

}

Ezek után képezhetünk egy tömböt, melynek egyes elemei hol Man, hol Woman típusúak lehetnek:

Person[] p = new Person [20];

p[1] = new Man();

p[2] = new Woman();

A programban elôforduló p[n].pressToothPaste() módszerhívásról a fordítóprogram még nem tudja eldönteni, hogy p adott indexû helyén épp férfival vagy nôvel akadt dolga. Ez csak a konkrét futáskor derül ki, akkor kell majd kiválasztani a két pressToothPaste() közül az alkalmazandót. C++ programozók, figyelem: ott ezt a mûködést virtuális függvényhívásnak hívják, és minden esetben külön szükséges a programban deklarálni. A Jávában az összes módszer virtuális! A példa azt is illusztrálja, hogy egy szülô típusú referencia esetén minden további nélkül használhatunk gyerek típusra való hivatkozást. Egyébként itt is igaz a típusátformálás (type casting) fogalma, de kötöttebb a dolog, mert az átformálás csak a referencia típusát érinti, magát az objektumot nem; nem lehet akármilyen objektum típusát átformálni, csak az öröklôdési láncban felfelé vagy lefelé.

Interfészek

A C++-hoz képest újítás a Jáva interfész (interface) fogalma, a nyelv tervezôi az Objective-C hatását emlegetik. Egy interfész nem más, mint módszerek lenyomatának gyûjteménye, mégpedig olyan módszereké, amelyek egyidejû meglétét tartja a programozó fontosnak. Maga az interfész nem adja meg a módszerek törzsét, hanem írhatunk olyan osztályokat, amelyek megvalósítják, implementálják az interfészt, azaz konkrétan definiálják az interfészben felsorolt összes módszert.

Ennek nagy haszna, hogy az öröklôdési hierarchiában nem rokon osztályok is viselkedhetnek hasonlóan, az objektumorientált terminológia szerint azonos protokoll -- a módszergyûjtemény -- segítségével kommunikálnak.

Ha egy osztály megvalósít egy interfészt, azt a class A implements I { ... }

formában lehet kifejezni, de ennek az a következménye, hogy A-ban az összes I-beli módszert meg kell valósítani. Többszörös öröklés ugyan nincs, ám egy osztály egyidejûleg több interfészt is létrehozhat. Az interfészek nevei az osztályok neveivel csaknem azonos módon használhatók, a new parancs kivételével mindenhol szerepelhetnek, ahol egy osztály neve egy változó típusát definiálja. A futó programban majd dinamikusan eldôl, hogy az egyes esetekben mely osztály egyede valósítja meg a kívánt interfészt.

Kiss István


1