Reflexe (programování)
Reflexe je v objektově orientovaném programování schopnost programovacího jazyka zjistit za běhu informace o určitém programovém objektu. Obecně v programování je reflexe schopnost zjistit informace o programu a jeho syntaktické struktuře.
V objektově orientovaném programování je program rozdělen do tříd, kdy jednotlivá třída popisuje vnitřní strukturu objektu a jeho vnější rozhraní. Na základně tříd je možné tvořit jednotlivé objekty. Některé jazyky mají schopnost za běhu zjistit informace o daném programu. Tato schopnost se nazývá reflexe, s jejíž pomocí lze získat za běhu programu informace o typu objektu. V objektově orientovaném programování se dá říci, že vše je objekt, tak je tedy objektem i třída a jiné datové typy, o kterých lze zjistit požadované informace.
Využití
Schopnost reflexe je vhodná pro vzdálené zpracování, kdy jsou dva počítače a na jeden z nich přicházejí objekty z toho druhého a počítač, který objekty zpracovává, má možnost získat pomocí reflexe potřebné informace o daném typu objektu. Lze to využít v jakémkoli programu, který za běhu upravuje své chování vůči objektům, se kterými pracuje.
Reflexe v Javě
Informace, které potřebujeme, můžeme získat z instance třídy java.lang.Class. Tento class-objekt mají jak třídy, tak rozhraní i primitivní typy. Při zavádění daného typu do paměti je pomocí instance třídy ClassLoader vytvořen class-objekt, který lze využít při získávání informací o daném typu objektu.[1] Pokud je nutné zajistit dynamické chování programu, v tomto případě je vhodnější[zdroj?] využít jazyky jako Groovy, Jython, JRuby, jejichž překladače řeší dynamičnost pomocí reflexe. V případě, že se liší jednotlivé verze JVM svými knihovnami, pak je možné přizpůsobit chování programu verzi virtuálního stroje, na kterém aktuálně program běží.[2]
Za běhu programu je možné získat:
- Název typu
- Druh typu (interface, třída, výčtový typ)
- Anotace
- Atributy, konstruktory, metody a vnořené datové typy
S těmito informacemi získanými za běhu programu je následně možné například volat konstruktory, metody nebo zjišťovat a přiřazovat hodnoty atributů. Lze také zjistit informace o nedostupných členech, ale v běžných situacích k nim není přístup.
Získání existujícího class-objektu
Pokud je typ daného názvu již zaveden do paměti, tak je vrácen jeho class-objekt a nevytváří se nový.
Pokud známe typ objektu a nemáme jeho instanci, pak literálem Typ.class
private Class<? extends Color> clazz = Color.class; Field [] fields = clazz.getDeclaredFields(); //získání všech deklarovaných proměnných ze třídy
U každého objektu lze volat metodu getClass(), díky čemuž jsme schopni zjistit, jaké třídy je objekt instancí.
Trida trida = new Trida(); trida.getReflection().getAnnotations(); //získá anotace dané třídy
Získání class-objektu datového typu zadaného svým názvem
Pomocí statické metody Class.forName(String)
lze získat class-objekt typu se zadaným úplným názvem, tj. včetně názvu balíčku. Při použití modulů lze volánímClass.forName(Module, String)
požádat o class-objekt zadaného typu v zadaném modulu. Rozšířené možnosti nabízí metoda Class.forName(String, boolean, ClassLoader)
, jejíž druhý parametr zadává, zda má být daný typ inicializován, a třetí parametru specifikuje ClassLoader
, který má daný datový typ zavést.
Class.forName("java.lang.String"); Class.forName("Foo",true,this.getClass().getClassLoader());
Reflexní metody třídy Class v Javě
Třída Class definuje 71 metod, z toho jen 3 statické (forName(?));
Metody pro získání konstruktorů
Statický inicializátor (tj. konstruktor třídy) není možné získat. Získat lze pouze konstruktory instancí.
Constructor<T> getConstructor(Class<?>... parameterTypes) Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
Metody pro získání polí
U polí se zadává jenom název.
Field getField(String name) Field getDeclaredField(String name)
Metody pro získaní metod
Method getMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException
Všechny veřejné metody včetně zděděných
Method[] getMethods() throws SecurityException
Všechny s výjimkou zděděných
Method[] getDeclaredMethods() throws SecurityException Metody pro získání názvu: String getSimpleName() String getName() String toString()
Metody pro získání informací o daném druhu typu, reprezentovaném class-objektem
isAnnotation(), isAnonymousClass(), isArray(), isEnum(), isInterface(), isLocalClass(), isMemberClass(), isPrimitive(), isSynthetic()
Ostatní informace o typu
getPackage(), int getModifiers(), Class<? super T> getSuperclass(), Class<?> getComponentType()
Metody vracející reprezentanty veřejných členů
Constructor<?>[] getConstructors() Field[] getFields() Method[] getMethods() Class<?>[] getClasses() Annotation[] getAnnotations()
Metody vracející reprezentanty deklarovaných členů
Vrací soukromé členy, ale nevrací zděděné členy.
Constructor<?>[] getDeclaredConstructors() Field[] getDeclaredFields() Method[] getDeclaredMethods() Class<?>[] getDeclaredClasses() Annotation[] getDeclaredAnnotations()
Reflexe v C#
Jmenný prostor, který umožňuje v .NET používat reflexi se jmenuje System.Reflection. Základní cestou k metadatům typu v mechanismu reflexe je třída získat instanci třídy System.Type. Díky ní je možné získat rozličné informace o daném typu, včetně seznamu jeho členů. Může se tak udělat pomocí metody GetType() nebo pomocí operátoru typeof.
Type t = Type.GetType("System.Int32"); Type t2 = Type.GetType("MyNamespace.MyType", MyAssembly); Type t3 = typeof(System.Int32);
Rozdíl mezi těmito dvěma druhy je v tom, že GetType() se vyhodnocuje za běhu, zatímco operátor typem v době kompilace. Máme-li instanci třídy Type, máme přístup k metadatům, atributům nebo vytvářet nové instance typů. Vztahy mezi dědičnosti mezi reflexními typy .NET
Ve chvíli, kdy máme odkaz na některý z těchto elementů, tak můžeme pohybovat se vztahy mezi daným elementem a souvisejícími prvky, jak je uvedeno na následujícím obrázku.
Nejzákladnějším typem reflexe je v .NET třída Type. Reprezentuje metadata pro jednotlivé deklarace typů v aplikaci. Typy obsahují členy. Ty zahrnují konstruktory, proměnné, vlastnosti, události a metody. Typy mohou navíc obsahovat vnořené typy, které se typicky používají jako pomocné třídy. Typy jsou seskupené do modulů a moduly jsou obsažené v sestavách.[3]
Reflexe v PHP
Od 5. verze tohoto jazyka, kdy se přišlo s objekty, má PHP základní schopnost reflexe, avšak ne dostatečnou, proto se různé frameworky snaží o její rozšíření. O reflexi v tomto jazyce se stará třída Reflection. V základním PHP například nemůžeme zjistit nic o anotacích daného objektu.
$a = new A();
$reflector = new ReflectionClass('A');
//vezme všechny vlastnosti třídy A a uloží je do pole
$properties = $reflector->getProperties();[4]
Nette
Nette\Object usnadňuje i přístup k sebereflexi třídy pomocí metody getReflection(), která vrací objekt třídy ClassType.
$circle = new Circle; echo $circle->getReflection()->hasMethod('getArea'); // existuje metoda 'getArea' ? echo $circle->getReflection()->getName(); // vrací název třídy, tj. 'Circle'[5]
Zend
Zend_Reflection_Class dědí od základní třídy Reflection a přidává další funkčnost.
$r = new Zend_Reflection_Class($class); printf( "The class level docblock has the short description: %s\n". "The class level docblock has the long description:\n%s\n", $r->getDocblock()->getShortDescription(), $r->getDocblock()->getLongDescription()); // Get the declaring file reflection $file = $r->getDeclaringFile();
Reflexe v Objective-C
// Foo třída
@interface Foo : NSObject
- (void)hello;
@end
// bez reflexe
Foo *obj = [[Foo alloc] init];
[obj hello];
// s reflexí
id obj = [[NSClassFromString(@"Foo") alloc] init];
[obj performSelector: @selector(hello)];
Reflexe v Ruby
# bez reflexe obj = Foo.new obj.hellos reflexí class_name = "Foo" method = :hello obj = Kernel.const_get(class_name).new obj.send method
Reflexe v Perlu
# bez reflexe
my $foo = Foo->new;
$foo->hello;
# nebo
Foo->new->hello;
# s reflexí
my $class = "Foo"
my $constructor = "new";
my $method = "hello";
my $f = $class->$constructor;
$f->$method;
# nebo
$class->$constructor->$method;
Reflexe ve Visual Basic
' Využití GetType k získání informací o daném typu: Dim i As Integer = 42 Dim type As System.Type = i.GetType() System.Console.WriteLine(type) ' Využití reflexe k získání informací z Assembly: Dim info As System.Reflection.Assembly = GetType(System.Int32).Assembly System.Console.WriteLine(info) ' Využití GetType k získání informací o daném typu: Dim i As Integer = 42 Dim type As System.Type = i.GetType() System.Console.WriteLine(type) ' Využití reflexe k získání informací z Assembly: Dim info As System.Reflection.Assembly = GetType(System.Int32).Assembly System.Console.WriteLine(info)
Odkazy
Reference
- DANEČEK, Jiří. Reflexe [online]. 2014 [cit. 2014-11-07]. Dostupné v archivu pořízeném dne 2014-11-07.
- PECINOVSKÝ, Rudolf. Reflexe [online]. 2014 [cit. 2019-04-22]. Dostupné online.
- BĚHÁLEK, Marek. Reflexe v C# [online]. Dostupné online.
- The reflection class [online]. PHP.net Manual. Dostupné online.
- Extension of PHP language [online]. Nette. Dostupné online.