Reflexe (programování)

Z Wikipedie, otevřené encyklopedie
Skočit na: Navigace, Hledá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í[editovat | editovat zdroj]

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ě[editovat | editovat zdroj]

Informace, které potřebujeme, můžeme získat z objektu 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ší 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[editovat | editovat zdroj]

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, od jaké třídy je objekt instancí.

Trida trida = new Trida();
trida.getReflection().getAnnotations(); //získá anotace dané třídy

Získání i nového class-objektu[editovat | editovat zdroj]

Pomocí statické metody Class.forName(String), název typu musí být úplný. Umožňuje zjistit název potřebného typu až za běhu. Nebo pomocí statické metody Class.forName(String, boolean, ClassLoader), druhý parametr umožňuje zavést, ale neinicializovat typ se zadaným názvem. ClassLoader umožňuje definovat, odkud a jaký typ je možné získat.¨

Class.forName("java.lang.String");
Class.forName("Foo",true,this.getClass().getClassLoader());

Reflexní metody třídy Class v Javě[editovat | editovat zdroj]

Třída Class definuje 57 metod, z toho jen 2 statické (forName(?));

Metody pro získání konstruktorů[editovat | editovat zdroj]

Statický konstruktor není možné získat.

Constructor<T> getConstructor(Class<?>... parameterTypes)
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)

Metody pro získání polí[editovat | editovat zdroj]

U polí se zadává jenom název.

Field getField(String name)
Field getDeclaredField(String name)

Metody pro získaní metod[editovat | editovat zdroj]

Method getMethod(String name,
Class<?>... parameterTypes)
throws NoSuchMethodException,
SecurityException

Všechny veřejné metody včetně zděděných[editovat | editovat zdroj]

Method[] getMethods()
throws SecurityException

Všechny s výjimkou zděděných[editovat | editovat zdroj]

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[editovat | editovat zdroj]

isAnnotation(), isAnonymousClass(), isArray(), isEnum(), isInterface(), isLocalClass(), isMemberClass(), isPrimitive(), isSynthetic()

Ostatní informace o typu[editovat | editovat zdroj]

getPackage(), int getModifiers(), Class<? super T> getSuperclass(), Class<?> getComponentType()

Metody vracející reprezentanty veřejných členů[editovat | editovat zdroj]

Constructor<?>[] getConstructors()
Field[] getFields()
Method[] getMethods()
Class<?>[] getClasses()
Annotation[] getAnnotations()

Metody vracející reprezentanty deklarovaných členů[editovat | editovat zdroj]

Vrací soukromé členy, ale nevrací zděděné členy.

Constructor<?>[] getDeclaredConstructors()
Field[] getDeclaredFields()
Method[] getDeclaredMethods()
Class<?>[] getDeclaredClasses()
Annotation[] getDeclaredAnnotations()


Reflexe v C#[editovat | editovat zdroj]

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[editovat | editovat zdroj]

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[editovat | editovat zdroj]

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[editovat | editovat zdroj]

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[editovat | editovat zdroj]

// 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[editovat | editovat zdroj]

# 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[editovat | editovat zdroj]

# 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[editovat | editovat zdroj]

' 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[editovat | editovat zdroj]

Reference[editovat | editovat zdroj]

  1. DANEČEK, Jiří. Reflexe [online]. 2014. Dostupné online.  
  2. PECINOVSKÝ, Rudolf. Reflexe [online]. 2014. Dostupné online.  
  3. BĚHÁLEK, Marek. Reflexe v C# [online]. . Dostupné online.  
  4. The reflection class [online]. PHP.net Manual. Dostupné online.  
  5. Extension of PHP language [online]. Nette. Dostupné online.