A modern programozási nyelvek számos szolgáltatással kényeztetnek minket. Mindazonáltal marad még épp elég kihívás az ember számára, attól nem kell tartanunk, hogy elkényelmesednek az agytekervényeink. ;-)
A következőkben egy érdekes témakörrel szeretnék foglalkozni: a metódusok túlterheléséről (overload) és felülírásáról (override) lesz szó. Példákon keresztül tárgyalom a témakört, és bemutatásra kerül egy potenciális csapda is.
A témakört a Java szemszögéből kerül bemutatásra.
A metódusfelülírás a többalakúságot valósítja meg a Java-ban és a C++-ban is. (A metódus felülírás megvalósítása eltér a C++-belitől, ugyanis a Java esetében nem kell, pontosabban nem lehet virtuális függvényekkel bajlódni: alapból minden nyilvános(public) és védett(protected) metódus felülírható a származtatott osztályokban.)
Lássunk egy konkrét példát. A következő osztályhierarchiával dolgozunk:
class A <- class B <- class Cés az implementáció:
class A {
String name() { return "A"; }
}
class B extends A {
String name() { return "B"; }
}
class C extends B {
String name() { return "C"; }
}
Minden származtatott osztály felülírja a name() metódust. Teszteljük a többalakúságot működés közben:
// létrehozunk egy listát, amely A típusú elemeket tárol
List genericList = new ArrayList(3);
genericList.add(new A()); // dinamikus (runtime) típus A
genericList.add(new B()); // dinamikus (runtime) típus B
genericList.add(new C()); // dinamikus (runtime) típus C
System.out.println("A felülírt metódusok meghívása -> az objektum dinamikus típusa dönti el, melyik kerül meghívásra");
for(A elem : genericList)
{
System.out.println(elem.name());
}
A futás az elvárt eredményt produkálja:
A felülírt metódusok meghívása -> az objektum dinamikus típusa dönti el, melyik kerül meghívásra
A
B
C
Lássuk a túlterhelést.
Hozzuk létre egy metódusnak a túlterhelt változatait, amelyek mindössze a paraméter típusában térnek el egymástól:
static private void printName(A a) {
System.out.println("A");
}
static private void printName(B b) {
System.out.println("B");
}
static private void printName(C c) {
System.out.println("C");
}
A printName() metódusnak egy ciklusban átadjuk a listánk elemeit, remélve, hogy az előzőhöz hasonló kimenetet produkál:
for(A elem : genericList)
{
printName(elem);
}
Az eredmény:
A
A
A
Nem erre számítottunk, és ez egy alattomos hibaforrás is lehet. A polimorfizmus a felülírt metódusokra vonatkozik: az objektum dinamikus, futásideji típusa dönti el, hogy melyik metódus kerül meghívásra.
A túlterhelés esetében egy metódus paraméterként kapja meg az objektumot - tahát nem az objektum tagfüggvényéről van szó, ezért nem is kapcsolódik annak dinamikus, futásideji típusához. Éppen ezért a paraméter statikus, fordítás-idejű típusa alapján dől el, melyik metódus hívódik meg.
Amennyiben valamiért mégis elkerülhetetlen ez a fajta megvalósítás, akkor megoldható némi körbeprogramozással.
Az általánosabb paraméterű metódus leellenőrzi a bemenő paraméter dinamikus típusát, majd ha az származtatott típus, akkor meghívásra kerül a specializált változat:
/**
* ez egy workaround, ne alkalmazzuk, hacsak nem feltétlenül szükséges
*/
static private void printNameOK(A a) {
if(a instanceof C) {
printNameOK((C)a);
}
else if (a instanceof B) {
printNameOK((B)a);
}
else
System.out.println("A");
}
static private void printNameOK(B b) {
System.out.println("B");
}
static private void printNameOK(C c) {
System.out.println("C");
}
Ezáltal az elvárt kimenetet kapjuk:
A
B
C
Jó programozást!
Üdvözlettel,
Nyisztor Károly
| < Előző | Következő > |
|---|





