Рефлексија (програмирање)
У информатици, рефлексија је способност неког рачунарског програма за испитивање (види тип интроспекције) и измену своје структуре и понашања (конкретно вредности, мета-податке, особине и функције) у рантајму.[1]
Историјска позадина
уредиНајранији рачунари су програмирани на матерњем асемблер језику, који су били по себи одражавани као ова оригинална архитектура која може да се програмира дефинисањем инструкција као и коришћењем података само-модификујућег кода. Као програмирање се преселило у језике високог нивоа, као што је C, ово одражава способност несталу (ван малвера) до програмских језика са одразом уграђеним у њихове типове система појава.
Брајан Кантвел Смитова 1982 докторска дисертација[2][3] увела је појам рачунарске рефлексије у програмским језицима, као и појам мета-кружни преводилац као компонента 3-Lisp.
Примене
уредиРефлексија може да се користи за посматрање и допунавање извршавање програма на рантајму. Рефлексија оријентисана програм компонента може пратити извршење кућишта кода и може се модификовати према жељеном циљу у вези са тим кућиштем. Ово се обично постиже динамичком доделом програмског кода у рантајму.
У објектно оријентисаним програмским језицима као што су Јава, рефлексија омогућава преглед класа, интерфејса, поља и метода у току рада не знајући имена интерфејса, поља, метода компилације. Она такође омогућава примерну нових објеката и позивање метода.
Рефлексија се такође може користити за адаптирање датог програма у различитим ситуацијама динамике. На пример, размислите апликацију која користи две различите класе X
и Y
наизменично да обављају сличне операције. Без рефлексије оријентисаног програмирања, апликација може бити тешко кодирана да позове метод имена класеX
и класе Y
. Међутим, користећи рефлексија оријентисану парадигму програмирања, апликација може бити дизајнирана и написана да искористи рефлексију у циљу изазивања метода у класама X
и Y
без хард-кодирања имена метода. Рефлексија-оријентисано програмирање скоро увек захтева додатно знање, оквир, релационо мапирање, а објекат релевантност како би се искористио више генеричко извршење кода.
Рефлексија се често користи као део тестирања софтвера, као што је за стварање Рантајма/примена пробних објеката.
Рефлексија је такође кључна стратегија за метапрограмирања.
У неким објектно-оријентисаним програмским језицима, као што су C# и Јава, рефлексија може да се употреби да обори члан приступачног правила. На пример, рефлексија омогућава да промените вредност поља са ознаком "приватно" у независну класу библиотеке.
Имплементација
уредиЈезик за подршку рефлексије обезбеђује велики број функција које су доступне на рантајму које би иначе било тешко постићи у језику нижег нивоа. Неке од ових функција су могуће до:
- Откријте и модификује изворни код конструкција (као што је код блокова, класа, метода, протокола, итд) као објекти прве класе на рантајму.
- Претварање стринга који одговара симболичком имену класе или функције у односу на или упућивање на те класе или функције.
- Процените стринг као да је изјава изворног кода у рантајму.
- Креирајте нови тумач за језик бајтока да да нови смисао или циљ за програмирање конструкта.
Ове карактеристике могу се реализовати на различите начине. У МОО-у, рефлексија представља природан део свакодневног програмирања идиома. Када се зову глаголи (методе), разне варијабле као што је глагол (име глагола који се зове) и ово (предмет на који се назива глагол) су насељени да дају контекст позива. Безбедност обично управља приступом саговорничким штос програмно: Како је код саговорника () списак начина на који се тренутни глагол на крају зову, извођење тестова саговорника ()[1] (команде позивају оригиналног корисника) омогућава да се глагол заштити од неовлашћеног коришћења.
Састав језика се ослања на свој рантајм систем да пружи информације о изворном коду. Састав Objective-C извршења, на пример, бележи имена свих метода у блок извршењу, обезбеђујући сто да одговара оним са основним методама (или селекторе за ове методе) састава у програму. У састав језика који подржава рантајм стварање функција, као што је Common Lisp, рантајм окружење мора да садржи компајлер или преводиоца.
Рефлексија се може реализовати за језике који немају уграђене рефлексије објеката помоћу програма трансформације система да дефинишу аутоматске промене изворног кода.
Примери
уредиКод следеће код комадићи креирају инстанцу foo
класе Foo
, и позивају методу hello
. За сваки програмски језик, нормала и рефлексија на бази секвенце позива се приказује.
eC
уредиУ наставку је пример у eC-у:
// без рефлексије
Foo foo { };
foo.hello();
// са рефлексијом
Class fooClass = eSystem_FindClass(__thisModule, "Foo");
Instance foo = eInstance_New(fooClass);
Method m = eClass_FindMethod(fooClass, "hello", fooClass.module);
((void (*)())(void *)m.function)(foo);
ECMAScript
уредиУ наставку је пример у ECMAScript-у, и стога важи и за Јаваскрипт и ActionScript:
// без рефлексије
new Foo.hello()
// са рефлексијом
// под претпоставком да Foo борави у овде
new this['Foo']['hello']()
// или без претпоставке
new (eval('Foo'))['hello']()
// или једноставно
eval('new Foo.hello()')
Јава
уредиУ наставку је пример у Јави:
// без рефлексије
Foo foo = new Foo();
foo.hello();
// са рефлексијом
Object foo = Class.forName("complete.classpath.and.Foo").newInstance();
// Алтернативно: Објекат foo = Foo.class.newInstance();
Method m = foo.getClass().getDeclaredMethod("hello", new Class<?>[0]);
m.invoke(foo);
Objective-C
уредиСледећи пример у Objective-C-у имплицира OpenStep или се користи фондација Кит оквир:
// Foo класа.
@interface Foo : NSObject
- (void)hello;
@end
// Слање "здраво" на пример Foo без рефлексије.
Foo *obj = [[Foo alloc] init];
[obj hello];
// Слање "здраво" на пример Фоо са рефлексијом.
id obj = [[NSClassFromString(@"Foo") alloc] init];
[obj performSelector: @selector(hello)];
Делфи
уредиОвај Делфи пример претпоставља да TFoo класа је декларисана у јединици под називом Јединица 1:
uses RTTI, Unit1;
procedure WithoutReflection;
var
Foo: TFoo;
begin
Foo := TFoo.Create;
try
Foo.Hello;
finally
Foo.Free;
end;
end;
procedure WithReflection;
var
RttiContext: TRttiContext;
RttiType: TRttiInstanceType;
Foo: TObject;
begin
RttiType := RttiContext.FindType('Unit1.TFoo') as TRttiInstanceType;
Foo := RttiType.GetMethod('Create').Invoke(RttiType.MetaclassType, []).AsObject;
try
RttiType.GetMethod('Hello').Invoke(Foo, []);
finally
Foo.Free;
end;
end;
Ово је значајан пример, јер Делфи је без менаџера, потпуно природно састављен језик, за разлику од већине других језика који подржавају размишљање. Његова архитектура језика наслеђује од снажног-откуцаног Паскала, али са значајним утицајем од SmallTalk-а. Упоредите са осталим примерима овде, од којих су многи динамични или скрипте језици као што су Perl, Пајтон или PHP или језици са рантајма као Јава или C#.
Perl
уредиУ наставку је пример у Perl-у:
# без рефлексије
my $foo = Foo->new;
$foo->hello;
# или
Foo->new->hello;
# са рефлексијом
my $class = "Foo"
my $constructor = "new";
my $method = "hello";
my $f = $class->$constructor;
$f->$method;
# или
$class->$constructor->$method;
# са eval-ом
eval "new Foo->hello;";
PHP
уредиУ наставку је пример у PHP-у:
// без рефлексије
$foo = new Foo();
$foo->hello();
// са рефлексијом
$reflector = new ReflectionClass('Foo');
$foo = $reflector->newInstance();
$hello = $reflector->getMethod('hello');
$hello->invoke($foo);
// коришћење повратних позива
$foo = new Foo();
call_user_func(array($foo, 'hello'));
// коришћењем променљиве варијабле синтаксе
$className = 'Foo';
$foo = new $className();
$method = 'hello';
$foo->$method();
Пајтон
уредиУ наставку је пример у Пајтону:
# без рефлексије
obj = Foo()
obj.hello()
# са рефлексијом
class_name = "Foo"
method = "hello"
obj = globals()[class_name]()
getattr(obj, method)()
# са eval-ом
eval("Foo().hello()")
R
уредиУ наставку је пример у R-у:
# Без рефлексије, под претпоставком да foo () враћа С3-тип објекат који има методу "здраво"
obj <- foo()
hello(obj)
# са рефлексијом
the.class <- "foo"
the.method <- "hello"
obj <- do.call(the.class, list())
do.call(the.method, alist(obj))
Ruby
уредиУ наставку је пример у Рубију:
# без рефлексије
obj = Foo.new
obj.hello
# са рефлексијом
class_name = "Foo"
method = :hello
obj = Object.const_get(class_name).new
obj.send method
# са eval-ом
eval "Foo.new.hello"
Види још
уреди- Тип интроспекција
- Само-модификујући код
- Само-домаћински
- Парадигме програмирања
- Листа рефлектујућих програмских језика и платформи
- Огледало (програмирање)
Референце
уреди- ^ „A Tutorial on Behavioral Reflection and its Implementation by Jacques Malenfant et al.” (PDF). Архивирано из оригинала (PDF) 22. 02. 2016. г. Приступљено 15. 01. 2016.
- ^ Brian Cantwell Smith, Procedural Reflection in Programming Languages, Department of Electrical Engineering and Computer Science, Massachusetts Institute of Technology, PhD Thesis, 1982.
- ^ „Brian C. Smith. Reflection and semantics in a procedural language. Technical Report MIT-LCS-TR-272, Massachusetts Institute of Technology, Cambridge, Mass., January 1982.”. Архивирано из оригинала 13. 12. 2015. г. Приступљено 15. 01. 2016.
Литература
уреди- Jonathan M. Sobel and Daniel P. Friedman. An Introduction to Reflection-Oriented Programming (1996), Indiana University.
- Forman, Ira R.; Forman, Nate (2005). Java Reflection in Action. ISBN 978-1-932394-18-4.
- Forman, Ira R.; Danforth, Scott (1999). Putting Metaclasses to Work. ISBN 978-0-201-43305-0.
Спољашње везе
уреди- Reflection in logic, functional and object-oriented programming: a short comparative study
- An Introduction to Reflection-Oriented Programming
- Brian Foote's pages on Reflection in Smalltalk
- Java Reflection API Tutorial from Oracle