在计算机学中,反射式编程()或反射(),是指计算机程序在运行时()可以访问、检测和修改它本身状态或行为的一种能力。用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为。
要注意术语“反射”和“类型内省”()的关系。内省(或称“自省”)机制仅指程序在运行时对自身信息(称为元数据)的检测;反射机制不仅包括要能在运行时对程序自身信息进行检测,还要求程序能进一步根据这些信息改变程序状态或结构。,向过程式编程语言介入了“计算反射”的概念,并且引入自循環直譯器概念用作3-Lisp的一个组成部份。
特点
优点
支持反射的语言提供了一些在早期高级语言中难以实现的运行时特性。
- 可以在一定程度上避免硬编码,提供灵活性和通用性。
- 由于将部分信息检查工作从编译期推迟到了运行期,此举在提高了代码灵活性的同时,牺牲了一点点运行效率。
通过深入学习反射的特性和技巧,它的劣势可以尽量避免,但这需要许多时间和经验的积累。
例子
下列代码片段建立类Foo的一个实例foo,并调用它的方法PrintHello。对于每个编程语言,展示平常的和基于反射的调用序列。
C#
// 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);
Go
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)
}
Java
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
}
Perl
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;";
PHP
// 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);
Python
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()')
R
Without reflection, assuming foo() returns an S3-type object that has method "hello"
obj
Ruby
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"
常见应用
- 反射经常作为软件测试的一部分,比如运行时创建/实例化模拟对象。
- Java语言解析XML文件的技术用到了反射。
参见
- 程序自修改
- 反射式编程语言和平台列表
参考资料
引用
来源
*
外部链接
- [https://www-master.ufr-info-p6.jussieu.fr/2007/Ajouts/Master_esj20_2007_2008/IMG/pdf/malenfant-ijcai95.pdf Reflection in logic, functional and object-oriented programming: a short comparative study]
- [https://web.archive.org/web/20100204091328/http://www.cs.indiana.edu/~jsobel/rop.html An Introduction to Reflection-Oriented Programming]
- [http://www.laputan.org/#Reflection Brian Foote's pages on Reflection in Smalltalk]
- [http://docs.oracle.com/javase/tutorial/reflect/index.html Java Reflection API Tutorial] from Oracle
评论 (0)