反射可以按类名、构造器参数和方法签名调用代码。方法可能重载,因此要同时指定方法名和参数类型,不能只遍历名称后随便调用。

一个可直接运行的例子

需要 JDK 8 或更高版本。保存为 ReflectionDemo.java:

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class ReflectionDemo {
public static class GreetingClient {
private final String prefix;
public GreetingClient(String prefix) {
this.prefix = prefix;
}
public String greet(String name) {
return prefix + name;
}
}
public static void main(String[] args) throws ReflectiveOperationException {
Class<?> type = Class.forName("ReflectionDemo$GreetingClient");
Constructor<?> constructor = type.getConstructor(String.class);
Object client = constructor.newInstance("Hello ");
Method method = type.getMethod("greet", String.class);
Object result = method.invoke(client, "FlyCode");
System.out.println(result);
}
}

在该文件目录执行:

Terminal window
javac -encoding UTF-8 ReflectionDemo.java
java ReflectionDemo

输出 Hello FlyCode。内部类的运行时名称使用 $;getMethod 查找 public 方法;invoke 的第一个参数是目标实例,其后才是方法参数。

找不到类时检查 classpath,找不到方法时检查参数类型。被调用方法抛异常时,反射会用 InvocationTargetException 包装,原异常可以通过 getCause() 查看。实际系统应限制可调用的类和方法,不直接执行客户端随意提交的类名。

参考:Java 反射 API。