A módszeres osztály |
Előző két részünkben áttekintettük a Java Reflection két
osztályát, név szerint a Class, és a Constructor
osztályokat. Ehavi cikkünkre maradt a reflection egyik legérdekesebb
osztálya, vagyis az az osztály, amely magáról az osztály
tagfüggvényeiről szolgáltat információkat. Az osztály a Method nevet viseli, és ahhoz hogy tudjuk
használni, szükséges importálnunk a java.lang.reflect csomagból legalább a Method osztályt, viszont ajánlom a teljes reflectet
importra, mert akkor teljes egészében tudjuk használni, megszorítások nélkül
az összes reflection képességet. A Method osztály a java.lang.reflect.AccesibleObject –ből van származtatva, tehát
először hadd vegyük ezt szemügyre. Mint tudjuk, egy Java osztály
függvényeinek, illetve változóinak van egy hozzáférhetőségi szintje.
Ezek lehetnek: publikus (public), privát (private) illetve védett (protected), hogy csak az alapokat soroljam fel. Ahogy
szintén tudjuk, a publikus tagokat bárki elérheti, a protected tagokat csak a
származtatott osztályok látják, a privát tagok pedig egyedül az osztály
számára láthatóak. Az AccessibleObject osztálynak van egy metódusa, mely
bizonyos esetekben módosítani tudja ezeket a hozzáférési jogokat. A metódus a
setAccessible névre hallgat, és két változatban is
megtalálható. A metódus lényege viszont a következőkön alapul: a (az
egyik) paraméter egy boolean típus, amely true esetén a privát illetve protected
tagfüggvényeket publikus hozzáférésűvé változtatja, false esetén pedig használja (visszaállítja)
az osztályban megadott hozzáférési jogokat. Ez a metódus az
első lépésben meghívja az esetlegesen létező Security Manager
checkPermission metódusát, paraméterként átad egy java.lang.reflect.ReflectPermission
(”suppressAccesChecks”) objektumot. A checkPermission SecurityException kivételt dob, ha bizonyos okok miatt nincs jogunk megváltoztatni a
láthatósági jogokat (például egy privát konstruktor publikussá való tételének
esetén, mint a Class osztály
esetében). Amennyiben
sikerült a láthatóságát megváltoztatni az aktuális AccessibleObject –nek, a
Reflection segítségével elméletileg bármilyen műveletet elvégezhetünk
vele. |
Egy függvény
absztraktizálása |
És most, hogy tudjuk, miként lehet meghívni egy privát függvényt minden
körülmények közt, hát nézzünk szét picit a Method osztály háztáján. A Method osztály egy osztály egy darab
osztálymetódusáról szolgál információkkal, és ennek a metódusnak az
elérhetőségét is biztosítja. Egy Method objektumot nem tudunk explicit módon
létrehozni, hanem használnunk kell a Class osztály getDeclaredMethods
metódusát, amely egy Method tömböt ad vissza. A függvény csak a publikus metódusokat téríti vissza,
mégpedig az alaposztályoktól felfele, a legutolsó pozíciókon magának az
osztálynak a metódusai szerepelnek. A getDeclaredMethods függvény viszont már érdekesebb
eredményt ad: az osztály összes metódusát visszatéríti, függetlenül a
láthatósági megszorításokra. Viszont ez a függvény csak a megadott osztálynak
a függvényeit sorolja fel, az alaposztályokat figyelmen kívül hagyja. A Method osztálynak rengeteg érdekes függvénye
van, viszont ezeknek a leírása mind megtalálható a JAVA API –ban, ezért most
már csak az érdekesebbeket fogom bemutatni. Például a getParameterTypes visszad egy Class[] –t, és amint a neve is mondja, a tömbbe az
osztály paramétertípusai kerülnek. A getReturnType() egy árva Class –t ad vissza, ami az osztály visszatérési típusát jelenti. A getModifiers egy int értéket ad vissza, amit a Modifier osztály statikus isXXX metódusaival ki tudunk kódolni. Ami igazán
érdekes, az az, hogy miként lehet meghívni egy osztály privát függvényeit.
Elsősorban szükségünk lesz egy objektumra az említett osztályból, ezt a
múlt számban bemutatott technikával percek alatt létre tudjuk hozni. Miután
rendelkezünk egy objektummal, használjuk a Method osztály invoke függvényét, mely első paraméter
gyanánt az objektumot várja el, a második paraméter pedig legyen egy Object tömb (Object[]), mely az átadandó paramétereket fogja
képviselni. Következzen a példa: import java.lang.reflect.*; class Test { private String a; public Test(String arg1,
int arg2) { System.out.println("Test Class constructor:"+arg1+" "+arg2); a
= arg1+":"+arg2; } private void testMethodPrivate(String
par) { System.out.println("Inside private method:"+par+" a="+a); } public void testMethodPublic(String
par) { System.out.println("Inside public method:"+par+" a="+a); testMethodPrivate(par); } } public class Default { public static void main(String[] args)
{ try
{ Class
test = Class.forName("Test"); Constructor
cons[] = test.getDeclaredConstructors(); String
a = "Hello"; Object[]
paras = {a, new Integer(2)}; Test
testClass =
(Test)(cons[0].newInstance(paras)); Method[]
methods = test.getDeclaredMethods(); for(int i=0;i<methods.length;i++) { methods[i].setAccessible(true); System.out.println(methods[i].getName()); methods[i].invoke(testClass,new Object[]{a}); } } catch(Exception ex) { ex.printStackTrace(); } } } Tehát mint
látjuk, ez a múlt havi számunkból már ismerős program
"továbbfejlesztése".
Figyeljünk a methods[i].setAcessible(true) –ra, ha oda azt rakjuk, hogy false,
akkor szép IllegalAccessException
–nal elszáll a programunk. Vigyázzunk ezzel a metódussal, nagyon
"veszélyes" dolgokat tudunk művelni vele. A következő (és
egyben befejező számban) a kimaradt részeket fogjuk megtárgyalni, mint
az osztályváltozók, illetve kevés betekintést kapunk a java.security csomagba. |
Deák Ferenc |