Moje odkazy
vydáno: 13. 6. 2015 22:56, aktualizováno: 14. 6. 2015 12:40
Java je (primárně) objektově orientovaný jazyk a máme zde zapouzdření – k soukromým (privátním) proměnným cizího objektu nemůžeme přímo přistupovat – objekt si je může měnit jen sám a ostatním to může dovolit jen nepřímo přes svoje metody. Přesto Java nabízí způsob, jak zapouzdření obejít – reflexe.
K polím/proměnným (stejně jako k metodám, konstruktorům atd.) se dostaneme přes objekt java.lang.Class
reprezentující příslušnou třídu. Kód si zaobalíme do metody:
private static void nastav(Object objekt, String proměnná, Object hodnota)
throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
Field f = objekt.getClass().getDeclaredField(proměnná);
f.setAccessible(true);
f.set(objekt, hodnota);
// TODO: můžeme odchytávat výjimky a vyhazovat vlastní výjimku případně běhovou
}
Potom můžeme místo standardního:
NějakáTřída t = NějakáTřída();
t.setPromenna(x);
// případně:
t.verejnaPromenna = x;
napsat:
nastav(t, "proměnná", x); // ne "setProměnná", protože nejdeme přes metodu
// případně:
nastav(t, "veřejnáProměnná", x);
Což nám dává stejné možnosti jako dynamické programovací jazyky. Samozřejmě i se všemi nevýhodami (překlepy neodhalené kompilátorem, nečitelnost, neudržovatelnost, nemožnost refaktorovat kód…).
Něco na způsob polské notace :-)Že je reflexe pomalá, je známá věc. Ale o kolik je pomalejší? Napsal jsem si jednoduchý test, který různými způsoby nastavuje proměnnou objektu a měří časy. Test jsem pustil několikrát a hodnoty se různí, ale pro hrubou představu – tohle jsou typické časy:
přímý přístup: celkovýČas = 5 ms relativníČas = 100.00 % setter: celkovýČas = 5 ms relativníČas = 100.00 % reflexe: celkovýČas = 151 ms relativníČas = 3020.00 % reflexe připravená: celkovýČas = 16 ms relativníČas = 320.00 %
Absolutní časy jsou pro milion opakování – zajímavější jsou ale relativní časy, zpomalení.
Přístup přes setter je srovnatelný s přímým přístupem k veřejné proměnné. Někdy byl dokonce rychlejší (náhoda).
Nastavení hodnoty pomocí reflexe v případě, že pokaždé znovu hledáme pole (java.lang.reflect.Field
) dané třídy podle názvu (viz metoda nastav()
výše) je cca 30× pomalejší.
Pokud ale pole ve třídě najdeme jen jednou (což pak můžeme aplikovat na různé instance dané třídy – Field
se váže ke třídě nikoli konkrétní instanci), tak už je čas jen 3× horší než přímý přístup nebo setter.
Třikrát nebo dokonce třicetkrát horší čas vypadá na první pohled hrozně, ale ve výsledku to může být zanedbatelné – pod hranicí měřitelnosti. Program totiž typicky stráví o X řádů víc času výpočtem hodnot nebo jejich získáváním a odesíláním (síť, databáze, disk atd.), než jejich nastavováním do proměnné objektu.
Troufám si tvrdit, že reflexe do kódu aplikací nepatří. Nejde až tak o výkon, jako spíš čitelnost a udržovatelnost. Kvůli reflexi se připravíte o pohodlí a spolehlivost dané typovou kontrolou (jedna z největších výhod oproti dynamickým jazykům).
Přesto se najdou případy, kdy dává reflexe smysl:
I v těchto případech je ale dobré s reflexí šetřit a používat ji s rozumem. Také zvažte použití již existující knihovny než začnete psát vlastní.
Témata: [softwarové inženýrství] [Java]
Tento článek zatím nikdo nekomentoval