名称反射用于描述能够检查同一系统(或其自身)中的其他代码的代码。
例如,假设您在 Java 中有一个未知类型的对象,并且您希望在其上调用 “doSomething” 方法(如果存在)。 Java 的静态类型系统并不是真的设计为支持这个,除非对象符合已知的接口,但是使用反射,你的代码可以查看对象并找出它是否有一个名为'doSomething' 的方法然后如果你调用它想要。
所以,在 Java 中给你一个代码示例(假设有问题的对象是 foo):
Method method = foo.getClass().getMethod("doSomething", null);
method.invoke(foo, null);
Java 中一个非常常见的用例是带注释的用法。例如,JUnit 4 将使用反射来查看使用 @Test 注释标记的方法的类,然后在运行单元测试时调用它们。
有一些很好的反思示例可以帮助您入门http://docs.oracle.com/javase/tutorial/reflect/index.html
最后,是的,这些概念在支持反射的其他静态类型语言(如 C#)中非常相似。在动态类型语言中,上述用例不太必要(因为编译器将允许在任何对象上调用任何方法,如果不存在则在运行时失败),但第二种情况是查找标记的方法或以某种方式工作仍然很常见。
评论更新:
检查系统中的代码并查看对象类型的能力不是反射,而是类型自省。然后反思是通过利用内省在运行时进行修改的能力。这里的区别是必要的,因为有些语言支持内省,但不支持反思。一个这样的例子是 C ++
反射是一种语言在运行时检查和动态调用类,方法,属性等的能力。
例如,Java 中的所有对象都有方法getClass()
,它允许您确定对象的类,即使您在编译时不知道它(例如,如果您将其声明为Object
) - 这可能看似微不足道,但是这样在诸如C++
类的动态较少的语言中,反射是不可能的。更高级的用法允许您列出和调用方法,构造函数等。
反射非常重要,因为它允许您编写不必在编译时 “了解” 所有内容的程序,使它们更具动态性,因为它们可以在运行时绑定在一起。代码可以针对已知接口编写,但是可以使用配置文件中的反射来实例化要使用的实际类。
由于这个原因,许多现代框架广泛使用反射。大多数其他现代语言也使用反射,并且在脚本语言(例如 Python)中,它们甚至更紧密地集成,因为在这些语言的通用编程模型中感觉更自然。
我最喜欢使用的反射之一是下面的 Java 转储方法。它将任何对象作为参数,并使用 Java 反射 API 打印出每个字段名称和值。
import java.lang.reflect.Array;
import java.lang.reflect.Field;
public static String dump(Object o, int callCount) {
callCount++;
StringBuffer tabs = new StringBuffer();
for (int k = 0; k < callCount; k++) {
tabs.append("\t");
}
StringBuffer buffer = new StringBuffer();
Class oClass = o.getClass();
if (oClass.isArray()) {
buffer.append("\n");
buffer.append(tabs.toString());
buffer.append("[");
for (int i = 0; i < Array.getLength(o); i++) {
if (i < 0)
buffer.append(",");
Object value = Array.get(o, i);
if (value.getClass().isPrimitive() ||
value.getClass() == java.lang.Long.class ||
value.getClass() == java.lang.String.class ||
value.getClass() == java.lang.Integer.class ||
value.getClass() == java.lang.Boolean.class
) {
buffer.append(value);
} else {
buffer.append(dump(value, callCount));
}
}
buffer.append(tabs.toString());
buffer.append("]\n");
} else {
buffer.append("\n");
buffer.append(tabs.toString());
buffer.append("{\n");
while (oClass != null) {
Field[] fields = oClass.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
buffer.append(tabs.toString());
fields[i].setAccessible(true);
buffer.append(fields[i].getName());
buffer.append("=");
try {
Object value = fields[i].get(o);
if (value != null) {
if (value.getClass().isPrimitive() ||
value.getClass() == java.lang.Long.class ||
value.getClass() == java.lang.String.class ||
value.getClass() == java.lang.Integer.class ||
value.getClass() == java.lang.Boolean.class
) {
buffer.append(value);
} else {
buffer.append(dump(value, callCount));
}
}
} catch (IllegalAccessException e) {
buffer.append(e.getMessage());
}
buffer.append("\n");
}
oClass = oClass.getSuperclass();
}
buffer.append(tabs.toString());
buffer.append("}\n");
}
return buffer.toString();
}