Gyakorlati alapok III.
Öröklődés (inheritance)
Statikus és dinamikus kötés
Statikus kötés (static binding)
Dinamikus kötés (dynamic binding)
Az előző fejezetben a metódus felülírásának szabályaival (overriding) ismerkedtünk meg.
A metódus-felülírás természetesen újabb, más jellegű problémákat is szül, nevezetesen, utána mikor és melyik objektum lesz elérhető, megszólítható, beazonosítható (azaz éppen melyik fut a műveleti memóriában).
Ebben a rövid fejezetben ennek további következményeit ismertetjük.
Az alább ismertetett, futtatható Java-példakód belső osztályok segítségével mutatja meg a jelenséget, amely rövid, tömör és 1 oldalon kifejthető kódbemutatást tesz lehetővé. Nézzük meg a kiindulási körülményeket:
-
van 1 általános Jarmu osztályunk, amelyből származtatunk 1 Auto osztályt,
-
a származtatás során az Auto osztály örökli a Jarmu osztály start() metódusát, amelyet azonban az utódosztályban felülírunk,
-
ezután létrehozzuk az objektumokat, amelytől a kiindulási kódunk így fog kinézni:
public class
Main {
public static void main(String args[]) {
Jarmu jarmu = new Jarmu();
Auto auto = new Auto();
jarmu.start();
auto.start();
}
}
class Jarmu {
public void start() {
System.out.println("A Jarmu startol.");
}
}
class Auto extends Jarmu {
public void start() {
System.out.println("Az Auto startol.");
}
}
Végeredmény:
A Jarmu startol.
Az Auto startol.
Ebben még nincs semmi különleges, hiszen a start() metódust felülírtuk, de az egyértelmű példányosítással...
-
Jarmu jarmu = new Jarmu();
-
Auto auto = new Auto();
...a JVM számára jeleztük, hogy melyik start() metódus fusson le:
-
jarmu.start();
-
auto.start();
Az ügy akkor kezd bonyolulttá válni, amikor Jarmu típusú Auto objektumot hozunk létre...
-
Jarmu jarmu = new Auto();
...mert ekkor egy típusában egyértelmű (Jarmu), de mégis "hibrid" objektumot hozunk létre. Itt merül fel a statikus és a dinamikus kötés választási lehetősége.
Statikus kötés (static binding)
Ha a metódus az osztályban static jelzővel illetett, akkor az egyértelműen az alaposztályához köti (azaz osztálymetódus). Ha a metódus felülírt és felé hívás történik, annak keresése a hívó osztálytól indul és a hierarchiában felfelé, az ősosztályok felé halad. Az alábbi futtatható Java-kódban ezt láthatjuk, hiszen a jarmu.start() hívással a Jarmu osztály start() metódusa fog lefutni (figyeljük meg, hogy mindkét osztályban a start() metódus static!):
public class
Main {
public static void main(String args[]) {
Jarmu jarmu = new Auto();
jarmu.start();
}
}
class Jarmu {
public static void start() {
System.out.println("A Jarmu startol.");
}
}
class Auto extends Jarmu {
public static void start() {
System.out.println("Az Auto startol.");
}
}
Végeredmény:
A Jarmu startol.
Dinamikus kötés (dynamic binding)
Ha a metódus az osztályban nem static jelzővel illetett, akkor nincs olyan momentum, amely egyértelműen az alaposztályához kötné (azaz példánymetódus). A kötés ekkor csakis dinamikus lehet, ami azért érdekes helyzet, mert előre senki sem tudhatja (legfőképpen a JVM nem), hogy éppen melyik példánymetódus fut, azaz a kötés csakis a futási idő alatt jöhet létre. Ezért illetik egyúttal a dinamikus kötést a következő jelzőkkel...
-
futás alatti kötés - runtime binding,
-
késői kötés - late binding,
...illetve dinamikus kötés alatti példánymetódus-keresés folyamatát dinamikus metóduskeresésnek (dynamic method lookup). A keresés végeredménye ebben az esetben csakis az lehet, hogy az éppen aktuálisan futó objektum kerül végrehajtásra, itt az Auto osztály felülírt start() metódusa:
public class
Main {
public static void main(String args[]) {
Jarmu jarmu = new Auto();
jarmu.start();
}
}
class Jarmu {
public void start() {
System.out.println("A Jarmu startol.");
}
}
class Auto extends Jarmu {
public void start() {
System.out.println("Az Auto startol.");
}
}
Végeredmény:
Az Auto startol.