Načítanie polí z triedy Java pomocou reflexie

1. Prehľad

Reflexia je schopnosť počítačového softvéru kontrolovať jeho štruktúru za behu programu. V Jave to dosiahneme použitím Rozhranie Java Reflection API. Umožňuje nám to kontrolovať prvky triedy, ako sú polia, metódy alebo dokonca vnútorné triedy, a to všetko za behu.

Tento výukový program sa zameria na to, ako načítať polia triedy Java, vrátane súkromných a zdedených polí.

2. Načítanie polí z triedy

Najprv sa pozrime, ako získať polia triedy bez ohľadu na ich viditeľnosť. Neskôr uvidíme, ako získať aj zdedené polia.

Začnime príkladom a Osoba trieda s dvoma String polia: priezvisko a krstné meno. Prvý je chránené (to bude užitočné neskôr), zatiaľ čo druhý je súkromné:

verejná trieda Osoba {chránený reťazec priezvisko; private String meno; }

Chceme získať oboje priezvisko a krstné meno polia pomocou odrazu. Dosiahneme to použitím Trieda :: getDeclaredFields metóda. Ako naznačuje jeho názov, vráti sa to všetko vyhlásil polia triedy vo forme a Lúka pole:

verejná trieda PersonAndEmployeeReflectionUnitTest {/ * ... konštanty ... * / @Test public void givenPersonClass_whenGetDeclaredFields_thenTwoFields () {Field [] allFields = Person.class.getDeclaredFields (); assertEquals (2, allFields.length); assertTrue (Arrays.stream (allFields) .anyMatch (field -> field.getName (). equals (LAST_NAME_FIELD) && field.getType (). equals (String.class))); assertTrue (Arrays.stream (allFields) .anyMatch (field -> field.getName (). equals (FIRST_NAME_FIELD) && field.getType (). equals (String.class))); }}

Ako vidíme, dostaneme dve polia Osoba trieda. Skontrolujeme ich názvy a typy, ktoré zodpovedajú definíciám polí v Osoba trieda.

3. Načítanie zdedených polí

Pozrime sa teraz, ako získať zdedené polia triedy Java.

Na ilustráciu si vytvorme druhú triedu s názvom Zamestnanec predlžujúci sa Osobas vlastným poľom:

public class Zamestnanec rozširuje Person {public int employeeId; }

3.1. Načítanie zdedených polí v hierarchii jednoduchých tried

Použitím Employee.class.getDeclaredFields () vráti iba zamestnanecké ID lúka, pretože táto metóda nevracia polia deklarované v nadtriedach. Aby sme dostali aj zdedené polia, musíme dostať aj polia Osoba nadtrieda.

Samozrejme by sme mohli použiť getDeclaredFields () metóda na oboch Osoba a Zamestnanec triedy a zlúčiť ich výsledky do jedného poľa. Čo však v prípade, ak nechceme výslovne špecifikovať nadtriedu?

V tomto prípade, môžeme použiť inú metódu Rozhranie Java Reflection API: Trieda :: getSuperclass. Získate tak nadtriedu inej triedy bez toho, aby ste potrebovali vedieť, čo to nadtrieda je.

Zozbierajme výsledky getDeclaredFields () na Zamestnanec.trieda a Employee.class.getSuperclass () a zlúčiť ich do jedného poľa:

@Test public void givenEmployeeClass_whenGetDeclaredFieldsOnBothClasses_thenThreeFields () {Field [] personFields = Employee.class.getSuperclass (). GetDeclaredFields (); Pole [] employeeFields = Employee.class.getDeclaredFields (); Pole [] allFields = nové Pole [employeeFields.length + personFields.length]; Arrays.setAll (allFields, i -> (i <personFields.length? PersonFields [i]: employeeFields [i - personFields.length])); assertEquals (3, allFields.length); Pole lastNameField = allFields [0]; assertEquals (LAST_NAME_FIELD, lastNameField.getName ()); assertEquals (String.class, lastNameField.getType ()); Pole firstNameField = allFields [1]; assertEquals (FIRST_NAME_FIELD, firstNameField.getName ()); assertEquals (String.class, firstNameField.getType ()); Field employeeIdField = allFields [2]; assertEquals (EMPLOYEE_ID_FIELD, employeeIdField.getName ()); assertEquals (int.class, employeeIdField.getType ()); }

Vidíme tu, že sme zhromaždili dve polia Osoba ako aj jednotné pole Zamestnanec.

Ale je súkromné oblasť Osoba naozaj zdedene pole? Nie veľmi. To by bolo rovnaké pre a balík-súkromné lúka. Iba verejné a chránené polia sa považujú za zdedené.

3.2. Filtrovanie verejné a chránené Polia

Bohužiaľ, žiadna metóda v rozhraní Java API nám neumožňuje zhromažďovanie verejné a chránené polia z triedy a jej nadtried. The Trieda :: getFields metóda sa blíži k nášmu cieľu, pretože vráti všetko verejné polia triedy a jej nadtriedy, ale nie chránené tie.

Jediným spôsobom, ako musíme získať iba zdedené polia, je použitie getDeclaredFields () metódu, ako sme to práve urobili, a filtrovať jej výsledky pomocou Field :: getModifiers metóda. Tento vracia int predstavujúce modifikátory aktuálneho poľa. Každému možnému modifikátoru je medzi nimi pridelená mocnina dvoch 2^0 a 2^7.

Napríklad, verejné je 2^0 a statický je 2^3. Preto volá getModifiers () metóda na a verejné a statický pole by sa vrátilo 9.

Potom je možné vykonať a bitové a medzi touto hodnotou a hodnotou konkrétneho modifikátora, aby ste zistili, či dané pole daný modifikátor má. Ak operácia vráti niečo iné ako 0, potom sa použije modifikátor, inak nie.

Máme šťastie, pretože Java nám poskytuje triedu nástrojov na kontrolu, či sú modifikátory obsiahnuté v hodnote vrátenej parametrom getModifiers (). Použime isPublic () a isProtected () metódy na zhromaždenie iba zdedených polí v našom príklade:

Zoznam 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 (field -> field.getName (). equals (LAST_NAME_FIELD) && field.getType (). equals (String.class)));

Ako vidíme, výsledok nenesie súkromné pole už.

3.3. Získavanie zdedených polí v hierarchii hlbokých tried

Vo vyššie uvedenom príklade sme pracovali na hierarchii jednej triedy. Čo urobíme teraz, ak máme hlbšiu triednu hierarchiu a chceme zhromaždiť všetky zdedené polia?

Predpokladajme, že máme podtriedu Zamestnanec alebo nadtrieda Osoba - potom získanie polí celej hierarchie bude vyžadovať kontrolu všetkých nadtried.

Môžeme to dosiahnuť vytvorením úžitkovej metódy, ktorá prechádza hierarchiou, a vytvorí pre nás úplný výsledok:

Zoznam getAllFields (trieda clazz) {if (clazz == null) {return Collections.emptyList (); } Výsledok zoznamu = nový ArrayList (getAllFields (clazz.getSuperclass ())); Zoznam filtrovaných polí = Arrays.stream (clazz.getDeclaredFields ()) .filter (f -> Modifier.isPublic (f.getModifiers ()) || Modifier.isProtected (f.getModifiers ())) .collect (Collectors.toList () ); result.addAll (filtrovanéPole); návratový výsledok; }

Táto rekurzívna metóda bude hľadať verejné a chránené polí cez hierarchiu tried a vráti všetko, čo bolo nájdené v a Zoznam.

Poďme si to ilustrovať malým testom na novom Zamestnanec triedy, rozširujúca Zamestnanec jeden:

public class MonthEmployee rozširuje Employee {chránená dvojnásobná odmena; }

Táto trieda definuje nové pole - odmena. Vzhľadom na celú triedu hierarchie by naša metóda mala obsahovať nasledujúce polia definície: Osoba :: priezvisko, zamestnanec :: employeeId a Zamestnanec mesiac :: odmena.

Zavolajme getAllFields () metóda na Zamestnanec:

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

Podľa očakávania zhromažďujeme všetky verejné a chránené polia.

4. Záver

V tomto článku sme videli, ako získať polia triedy Java pomocou príkazu Java Reflection API.

Najprv sme sa naučili, ako načítať deklarované polia triedy. Potom sme videli, ako získať aj jeho polia nadtriedy. Potom sme sa naučili odfiltrovaťverejné a ne-chránené polia.

Nakoniec sme videli, ako to všetko použiť na zhromaždenie zdedených polí hierarchie viacerých tried.

Celý kód tohto článku je ako obvykle k dispozícii na našom GitHub.


$config[zx-auto] not found$config[zx-overlay] not found