Remove ads
计算机程序检查其程序本身的能力 来自维基百科,自由的百科全书
在计算机学中,反射式编程(英語:reflective programming)或反射(英語:reflection),是指计算机程序在运行时(runtime)可以访问、检测和修改它本身状态或行为的一种能力。[1]用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为。
要注意术语“反射”和“内省”(type introspection)的关系。内省(或称“自省”)机制仅指程序在运行时对自身信息(称为元数据)的检测;反射机制不仅包括要能在运行时对程序自身信息进行检测,还要求程序能进一步根据这些信息改变程序状态或结构。[1]
反射用于观察并修改程序在运行时的行为。一个反射導向的程式组件可以监测一个范围内的代码执行情况,可以根据获取的目标对象信息及与此相关的范围修改自身。这可通过在运行时动态分配程序代码实现。
在类型检测严格的面向对象的编程语言如Java中,一般需要在编译期间对程序中需要调用的对象的具体类型、介面(interface)、資料成員(fields)和方法的合法性进行检查。反射技术则允许将对需要调用的物件的訊息检查工作从编译期间推迟到运行期间再现场执行。这样一来,可以在编译期间先不明确目标物件的介面(interface)名称、字段(fields),即物件的資料成員(成员变量)、可用方法,然后在运行根据目标物件自身的訊息决定如何处理。它还允许根据判断结果进行实例化新物件和相关方法的呼叫。
反射主要用途就是使给定的程式,动态地适应不同的运行情况。利用物件導向建模中的多型(多态性)也可以简化编写分别适用于多种不同情形的功能代码,但是反射可以解决多型(多态性)并不适用的更普遍情形,从而更大程度地避免硬编码(即把代码的细节“写死”,缺乏灵活性)的代码风格。
反射也是元编程的一个关键策略。
早期计算机的原生汇编语言本质上就具有反射特性。因为这些最初架构可以通过定义指令作为数据及使用自修改代码来编程,实现反射功能是很平常的。编程发展到使用编译型高级语言如Algol、Cobol、Fortran和包括Pascal和C在内的很多其他语言时,自修改代码等实践很大程度上消失了,直到将反射特性内建入类型系统的高级编程语言出现后才再次提供了反射功能。Lisp语言家族以具有同像性作为标志性特征,可以认为具有反射性。
1982年,布莱恩·史密斯在其博士论文《编程语言中的过程式反射》中[2],向过程式编程语言介入了“计算反射”的概念,并且引入自循環直譯器概念用作3-Lisp的一个组成部份[3]。
支持反射的语言提供了一些在早期高级语言中难以实现的运行时特性。
通过深入学习反射的特性和技巧,它的劣势可以尽量避免,但这需要许多时间和经验的积累。[4]
下列代码片段建立类Foo的一个实例foo,并调用它的方法PrintHello。对于每个编程语言,展示平常的和基于反射的调用序列。
// Without reflection
Foo foo = new Foo();
foo.PrintHello();
// With reflection
System.Object foo2 = System.Activator.CreateInstance(System.Type.GetType("complete.classpath.and.Foo"));
System.Reflection.MethodInfo method = foo2.GetType().GetMethod("PrintHello");
method.Invoke(foo2, null);
import "reflect"
// Without reflection
f := Foo{}
f.Hello()
// With reflection
fT := reflect.TypeOf(Foo{})
fV := reflect.New(fT)
m := fV.MethodByName("Hello")
if m.IsValid() {
m.Call(nil)
}
import java.lang.reflect.Method;
// Without reflection
Foo foo = new Foo();
foo.hello();
// With reflection
try {
// Alternatively: Object foo = Foo.class.newInstance();
Object foo = Class.forName("complete.classpath.and.Foo").newInstance();
Method m = foo.getClass().getDeclaredMethod("hello", new Class<?>[0]);
m.invoke(foo);
} catch (Exception e) {
// Catching ClassNotFoundException, NoSuchMethodException
// InstantiationException, IllegalAccessException
}
# Without reflection
my $foo = Foo->new;
$foo->hello;
# or
Foo->new->hello;
# With reflection
my $class = "Foo"
my $constructor = "new";
my $method = "hello";
my $f = $class->$constructor;
$f->$method;
# or
$class->$constructor->$method;
# with eval
eval "new Foo->hello;";
// Without reflection
$foo = new Foo();
$foo->hello();
// With reflection, using Reflections API
$reflector = new ReflectionClass('Foo');
$foo = $reflector->newInstance();
$hello = $reflector->getMethod('hello');
$hello->invoke($foo);
# Without reflection
obj = Foo()
obj.hello()
# With reflection
obj = globals()['Foo']() # globals() Return a dictionary representing the current global symbol table.
getattr(obj, 'hello')() # getattr(object, name) Return the value of the named attribute of object.
# With eval
eval('Foo().hello()')
# Without reflection, assuming foo() returns an S3-type object that has method "hello"
obj <- foo()
hello(obj)
# With reflection
the.class <- "foo"
the.method <- "hello"
obj <- do.call(the.class, list())
do.call(the.method, alist(obj))
# Without reflection
obj = Foo.new
obj.hello
# With reflection
class_name = "Foo"
method_name = :hello
obj = Object.const_get(class_name).new
obj.send method_name
# With eval
eval "Foo.new.hello"
Seamless Wikipedia browsing. On steroids.
Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.
Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.