Java programozási nyelv 5. rész – Osztályok III. Nyugat-Magyarországi Egyetem Faipari Mérnöki Kar Informatikai Intézet Soós Sándor 2005. szeptember
Tartalomjegyzék Polimorfizmus, ismétlés Túlterhelés és öröklődés Változók és az öröklődés A hozzáférési kategóriák és az öröklődés Protected hozzáférési kategória Az osztályhierarchia Absztrakt osztályok és metódusok Absztrakt osztályok kiterjesztése Példa absztrakt osztályra Végleges osztályok és metódusok Órai gyakorló feladat
Polimorfizmus, ismétlés Egy gyermek rendelkezik őseinek minden tulajdonságával, ezért minden környezetben használható, ahol az ős használható. Az automatikus típuskonverzió révén egy „ős” típusú változónak értékül adható egy „gyerek” típusú. Ezt nevezzük polimorfizmusnak. Egy változónak van statikus és dinamikus típusa: statikus típus: ami a deklarációban szerepel (állandó) dinamikus típus: az objektum pillanatnyi típusa (változhat) A polimorfizmus a metódusok felüldefiniálása révén teljesedik ki.
Túlterhelés és öröklődés Mi történik akkor, ha egy olyan osztályt terjesztünk ki, amiben vannak azonos nevű, túlterhelt metódusok? Ha ilyenkor felüldefiniálunk egy metódust, akkor az csak a pontosan azonos szignatúrájú metódust definiálja felül, a többit nem. A döntés fordítási időben történik, ezért a fordító csak a statikus típust tudja figyelembe venni, a dinamikusat nem.
Változók és az öröklődés A kiterjesztett osztály ősének minden változóját örökli, még akkor is, ha az közvetlenül nem látható. Definiálhatunk örökölttel azonos nevű változót is, ez elfedi az eredetit. Az elfedett változókat minősítéssel, vagy típuskényszerítéssel lehet elérni.
Csomagok, package Megállapodtunk abban, hogy minden osztályt önálló fájlba teszünk. Egy komolyabb program több tucat osztályból épül fel, ami több tucat file-t jelent. Az osztályok, illetve forrásfile-ok kategóriákba sorolását teszik lehetővé a csomagok. Az osztályok hierarchikus struktúrát alkotnak, ahogyan láttuk a java.lang esetében. A FreeJava korábbi verziói nem kezelik megfelelően a csomagokat!!! Használd a v1.01_T2004.08.28 verziót!
Hozzáférési kategóriák kiterjesztés nélkül Hasonlít a C++ -hoz, de van eltérés: public (nyilvános): mindenki elérheti, mint a C++ -ban üres (félnyilvános): csomagon belül public, azon kívül private private (privát): csak az osztályon belül érhető el, mint a C++ -ban protected (védett): a kiterjesztéskor lesz szerepe
A hozzáférési kategóriák és a kiterjesztés, öröklődés A nyilvános, félnyilvános és privát hozzáférési kategória értelemszerűen terjeszthető ki a leszármazott osztályokra: public: ősének public tagjaihoz természetesen korlátozás nélkül hozzáférhet a leszármazott osztály üres: ősének félnyilvános tagjaihoz csak akkor férhet hozzá a leszármazott, ha azzal azonos csomagba tartozik private: ősének private tagjaihoz a leszármazott sem férhet hozzá protected: a protected kategória figyelembe veszi az öröklési viszonyokat. Részletesen lásd a következő dián!
Protected hozzáférési kategória A protected kategória a félnyilvános kiterjesztése, ezért ... a protected tagokhoz hozzáférhetnek az azonos csomagban definiált osztályok egy másik csomagban definiált osztály akkor férhet hozzá egy protected taghoz, ha leszármazottja a tagot definiáló osztálynak, és a tagra minősítés nélkül hivatkozik, vagy olyan minősítéssel hivatkozik, amelynek típusa ő maga, vagy leszármazottja. Példaként lásd a következő diát! egy protected kategóriájú konstruktort más csomagba tartozó gyermek csak a super kulcsszó segítségével hívhat, new-val példányosítani csak csomagon belül lehet!
Illusztráció egy protected taghoz való hozzáférés szabályaihoz class A { protected int p; } class B extends A { } class C extends A { } Ebben a helyzetben B egy metódusa hozzáférhet a p taghoz, ha nem használ minősítést, vagy a minősítés B, vagy D típusú de nem férhet hozzá A vagy C típusú minősítésen keresztül! class D extends B { }
Az osztályhierarchia Az osztályok rokonsági kapcsolatainak összességét osztályhierarchiának hívjuk. Javaban ezt egy fával ábrázolhatjuk, mert nem létezik többszörös öröklődés. A fa kiinduló pontjában áll a java.lang csomagban definiált Object osztály. Az Object minden osztálynak szülője, amelynek definíciójában nem adtunk meg extends-et. Az Object definiálja azokat a tagokat, amelyekre minden osztályban szükség van, pl. getClass, toString, equals.
Absztrakt osztályok és metódusok A polimorfizmust eddig a kódmegosztás révén hasznosítottuk, emellett azonban legalább ilyen nagy a jelentősége a program tervezése szempontjából. Egy „ősosztály” definiálásakor kialakítunk egy „közös nevezőt”, definiálunk egy olyan metóduskészletet, amelyet a leszármazottak mindegyike tartalmazni fog, így egységes módon kezelhetők lesznek. Gyakori megoldás az, hogy a közös ős csak ezt a közös felületet határozza meg, tényleges implementációt nem tartalmaz.
Absztrakt osztályok és metódusok 2 Ilyenkor csak a metódus fejét definiáljuk, a törzsét nem. Az ilyen törzs nélküli metódust nevezzük absztrakt metódusnak, az abstract kulcsszóval jelöljük. Azt az osztályt, amiben van legalább egy absztrakt metódus, absztrakt osztálynak nevezzük és szintén az abstract kulcsszóval jelöljük. Az absztrakt osztályok nem példányosíthatók, azonban ilyen típusú változót lehet deklarálni. Van-e értelme ennek? Miért hasznos ez?
Absztrakt osztályok kiterjesztése Az absztrakt osztályokat ki kell terjeszteni, hogy az absztrakt metódusok implementációt kapjanak. Ilyenkor a kiterjesztő osztály felüldefiniálja az absztrakt metódus(oka)t. Ezt úgy mondjuk, hogy az osztály megvalósítja, vagy implementálja az absztrakt metódust. Nem kötelező, hogy a kiterjesztő osztály minden absztrakt metódust megvalósítson, de ellenkező esetben ő maga is absztrakt marad. Absztrakt metódus nem lehet: private, final, static, és native. Miért?
Példa absztrakt osztályra public abstract class Sikidom { private boolean keruletKiszamitva = false; private boolean teruletKiszamitva = false; private double kerulet; private double terulet; public double kerulet() { if (!keruletKiszamitva) { kerulet = keruletSzamit(); keruletKiszamitva = true; } return kerulet;
Példa absztrakt osztályra, folyt. public double terulet() { if (!teruletKiszamitva) { terulet = teruletSzamit(); teruletKiszamitva = true; } return terulet; protected abstract double keruletSzamit(); protected abstract double teruletSzamit(); } // az osztály vége
Példa az absztrakt osztály kiterjesztésére 1 public class Teglalap extends Sikidom { private double a, b; public Teglalap (double a, double b) { this.a = a; this.b = b; } protected double keruletSzamit () { return 2*(a+b); protected double teruletSzamit () { return a*b; } // az osztály vége
Példa az absztrakt osztály kiterjesztésére 2 public class Kor extends Sikidom { private double r; public Kor (double r) { this.r = r; } protected double keruletSzamit() { return 2*Math.PI*r; protected double teruletSzamit() { return r*r*Math.PI; } // az osztály vége
Végleges osztályok és metódusok Vannak olyan osztályok, illetve metódusok, amelyek működésének megváltoztatása nem lenne kívánatos. Ilyen például a java.lang.Object osztály getClass metódusa. Az ilyen metódusok felüldefiniálását a final módosítóval tilthatjuk meg. public class Object { public final Class getClass(); ... } Osztályra alkalmazva a final módosítót, meggátolhatjuk az osztály kiterjesztését. Természetesen a final és az abstract kizárja egymást!
Órai gyakorló feladat Tanulmányozzuk az előadásban szereplő Síkidomos példát! Készítsünk egy főprogramot az osztályok kipróbálására! Definiáljunk egy derékszögű háromszög osztályt!