反射可以按类名、构造器参数和方法签名调用代码。方法可能重载,因此要同时指定方法名和参数类型,不能只遍历名称后随便调用。
一个可直接运行的例子
需要 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); }}在该文件目录执行:
javac -encoding UTF-8 ReflectionDemo.javajava ReflectionDemo输出 Hello FlyCode。内部类的运行时名称使用 $;getMethod 查找 public 方法;invoke 的第一个参数是目标实例,其后才是方法参数。
找不到类时检查 classpath,找不到方法时检查参数类型。被调用方法抛异常时,反射会用 InvocationTargetException 包装,原异常可以通过 getCause() 查看。实际系统应限制可调用的类和方法,不直接执行客户端随意提交的类名。
参考:Java 反射 API。
评论