Mezők lekérése Java osztályból a Reflection használatával

1. Áttekintés

A reflexió a számítógépes szoftverek képessége arra, hogy futás közben megvizsgálja a szerkezetét. A Java-ban ezt a Java Reflection API. Ez lehetővé teszi számunkra, hogy futás közben ellenőrizzük az osztály elemeit, például mezőket, módszereket vagy akár belső osztályokat.

Ez az oktatóanyag arra összpontosít, hogy miként lehet lekérni egy Java osztály mezőit, beleértve a privát és az örökölt mezőket.

2. Mezők lekérése egy osztályból

Először nézzük meg, hogyan lehet lekérni egy osztály mezőit, függetlenül azok láthatóságától. Később meglátjuk, hogyan lehet örökölt mezőket is megszerezni.

Kezdjük egy a példával Személy osztály kettővel Húr mezők: vezetéknév és keresztnév. Az előbbi az védett (ez később hasznos lesz), míg ez utóbbi magán:

public class Személy {védett karakterlánc vezetéknév; privát karakterlánc keresztnév; }

Mindkettőt meg akarjuk szerezni vezetéknév és keresztnév mezők reflexióval. Ezt a Osztály :: getDeclaredFields módszer. Ahogy a neve is mutatja, ez adja vissza az összes jelentette ki osztály mezői, a formájában Terület sor:

public class PersonAndEmployeeReflectionUnitTest {/ * ... konstansok ... * / @Test public void givenPersonClass_whenGetDeclaredFields_thenTwoFields () {Field [] allFields = Person.class.getDeclaredFields (); assertEquals (2, allFields.length); assertTrue (Arrays.stream (allFields) .anyMatch (mező -> field.getName (). egyenlő (LAST_NAME_FIELD) && field.getType (). egyenlő (String.osztály))); assertTrue (Arrays.stream (allFields) .anyMatch (mező -> field.getName (). egyenlő (FIRST_NAME_FIELD) && field.getType (). egyenlő (String.osztály))); }}

Mint láthatjuk, megkapjuk a Személy osztály. Ellenőrizzük a nevüket és típusukat, amelyek megfelelnek a Személy osztály.

3. Az öröklött mezők lekérése

Most nézzük meg, hogyan lehet megszerezni egy Java osztály örökölt mezőit.

Ennek szemléltetésére hozzunk létre egy második osztályt, amelynek neve Munkavállaló kiterjedő Személy, saját területtel:

public class Alkalmazott kiterjeszti Person {public int workerId; }

3.1. Örökölt mezők lekérése egyszerű osztályhierarchiában

Használata Employee.class.getDeclaredFields () csak a munkavállalói azonosító terület, mivel ez a módszer nem adja vissza a szuperosztályokban deklarált mezőket. Az örökölt mezők megszerzéséhez meg kell kapnunk a Személy szuperosztály.

Természetesen használhatnánk a getDeclaredFields () módszer mindkettőn Személy és Munkavállaló osztályokat és eredményeiket egyetlen tömbbe egyesítik. De mi van, ha nem akarjuk kifejezetten megadni a szuperosztályt?

Ebben az esetben, felhasználhatjuk a Java Reflection API: Osztály :: getSuperclass. Ez egy másik osztály szuperosztályát adja nekünk, anélkül, hogy tudnunk kellene, mi ez a szuperosztály.

Gyűjtsük össze az eredményeket getDeclaredFields () tovább Alkalmazott.osztály és Employee.class.getSuperclass () és egyesítse őket egyetlen tömbbe:

@Test public void givenEmployeeClass_whenGetDeclaredFieldsOnBothClasses_thenThreeFields () {Field [] personFields = Employee.class.getSuperclass (). GetDeclaredFields (); Field [] workerFields = Employee.class.getDeclaredFields (); Mező [] allFields = új mező [fieldFields.length + personFields.length]; Arrays.setAll (allFields, i -> (i <personFields.length? PersonFields [i]: workerFields [i - personFields.length])); assertEquals (3, allFields.length); Mező lastNameField = allFields [0]; assertEquals (LAST_NAME_FIELD, vezetéknévField.getName ()); assertEquals (String.class, lastNameField.getType ()); Mező firstNameField = allFields [1]; assertEquals (FIRST_NAME_FIELD, keresztnévField.getName ()); assertEquals (String.class, firstNameField.getType ()); Helyi alkalmazottIdField = allFields [2]; assertEquals (EMPLOYEE_ID_FIELD, workerIdField.getName ()); assertEquals (int.osztály, workerIdField.getType ()); }

Itt láthatjuk, hogy összegyűjtöttük a két mezőt Személy valamint az egyetlen mező Munkavállaló.

De, az a magán területe Személy valóban öröklött terület? Nem túl sok. Ugyanez lenne a csomag-privát terület. Csak nyilvános és védett a mezőket örököltnek tekintik.

3.2. Szűrő nyilvános és védett Mezők

Sajnos a Java API egyetlen metódusa sem engedi meg az összegyűjtést nyilvános és védett mezők egy osztályból és annak szuperosztályaiból. A Osztály :: getFields módszer megközelíti a célunkat, mivel mindent visszaad nyilvános osztály osztályai és szuperosztályai, de nem védett azok.

Csak az öröklött mezőket kell megszereznünk, ha a getDeclaredFields () metódust, ahogyan mi most tettük, és szűrjük le eredményeit a Field :: getModifiers módszer. Ez ad vissza egy int az aktuális mező módosítóit ábrázolja. Minden lehetséges módosító kettőhöz van rendelve 2^0 és 2^7.

Például, nyilvános van 2^0 és statikus van 2^3. Ezért hívja a getModifiers () módszer a nyilvános és statikus mező értéke 9.

Ezután lehetséges a bitenként és ezen érték és egy adott módosító értéke között, hogy lássa, van-e az adott mezőben ez a módosító. Ha a művelet mást ad vissza, mint 0, akkor a módosító kerül alkalmazásra, különben nem.

Szerencsénk van, mivel a Java segédprogramot nyújt számunkra, hogy ellenőrizzük, vannak-e módosítók a visszaadott értékben getModifiers (). Használjuk a isPublic () és isProtected () módszerek csak az öröklött mezők összegyűjtésére a példánkban:

List personFields = Arrays.stream (Employee.class.getSuperclass (). GetDeclaredFields ()) .filter (f -> Modifier.isPublic (f.getModifiers ()) || Modifier.isProtected (f.getModifiers ()) .collect (Collectors.toList ()); assertEquals (1, personFields.size ()); assertTrue (personFields.stream (). anyMatch (mező -> field.getName (). egyenlő (LAST_NAME_FIELD) && field.getType (). egyenlő (String.osztály)));

Mint láthatjuk, az eredmény nem hordozza a következőket magán mező már.

3.3. Örökölt mezők lekérése mély osztály hierarchiában

A fenti példában egyetlen osztályhierarchián dolgoztunk. Mit tegyünk most, ha mélyebb osztályhierarchiával rendelkezünk, és szeretnénk összegyűjteni az összes örökölt mezőt?

Tegyük fel, hogy van egy alosztályunk Munkavállaló vagy szuperosztálya Személy - akkor a teljes hierarchia mezőinek megszerzéséhez meg kell vizsgálni az összes szuperosztályt.

Ezt úgy érhetjük el, hogy létrehozunk egy olyan segédprogram-módszert, amely végigfut a hierarchián, elkészítve számunkra a teljes eredményt:

List getAllFields (Osztály clazz) {if (clazz == null) {return Gyűjtemények.emptyList (); } Lista eredménye = new ArrayList (getAllFields (clazz.getSuperclass ())); List filteredFields = Arrays.stream (clazz.getDeclaredFields ()) .filter (f -> Modifier.isPublic (f.getModifiers ()) || Modifier.isProtected (f.getModifiers ())) .collect (Collectors.toList () ); result.addAll (filteredFields); visszatérési eredmény; }

Ez a rekurzív módszer keresni fog nyilvános és védett mezőket az osztályhierarchián keresztül, és visszaadja mindazokat, amelyeket a Lista.

Illusztráljuk egy új teszt kis tesztjével MonthEmployee osztály, meghosszabbítva a Munkavállaló egy:

public class MonthEmployee meghosszabbítja az Employee {védett kettős jutalmat; }

Ez az osztály új mezőt határoz meg - jutalom. Az összes hierarchiaosztályra való tekintettel a módszerünknek a következő mezőket kell megadnia definíciók: Személy :: vezetéknév, alkalmazott :: alkalmazottId és MonthEmployee :: jutalom.

Hívjuk a getAllFields () módszer be MonthEmployee:

@Test public void givenMonthEmployeeClass_whenGetAllFields_thenThreeFields () {List allFields = getAllFields (MonthEmployee.class); assertEquals (3, allFields.size ()); assertTrue (allFields.stream (). anyMatch (mező -> field.getName (). egyenlő (LAST_NAME_FIELD) && field.getType (). egyenlő (String.osztály))); assertTrue (allFields.stream (). anyMatch (mező -> field.getName (). egyenlő (EMPLOYEE_ID_FIELD) && field.getType (). egyenlő (int.osztály))); assertTrue (allFields.stream (). anyMatch (mező -> field.getName (). egyenlő (MONTH_EMPLOYEE_REWARD_FIELD) && field.getType (). egyenlő (double.class)); }

A várakozásoknak megfelelően összeszedjük az összes nyilvános és védett mezők.

4. Következtetés

Ebben a cikkben azt láttuk, hogyan lehet lekérni a Java osztály mezőit a Java Reflection API.

Először megtanultuk, hogyan lehet lekérni egy osztály deklarált mezőit. Ezt követően láttuk, hogyan lehet lekérni a szuperosztályú mezőket is. Aztán megtanultuk kiszűrni a nemnyilvános és nemvédett mezők.

Végül láttuk, hogyan lehet mindezt alkalmazni a több osztályú hierarchia öröklődő mezőinek összegyűjtésére.

Szokás szerint a cikk teljes kódja elérhető a GitHub oldalán.