运行时动态调用方法的核心是“先获取类、再找方法、最后调用”,依赖反射机制,可通过类名字符串、接口约定或注解扫描等方式实现,需处理classnotfoundexception、nosuchmethodexception等异常并注意安全风险。

在运行时不知道具体类名的情况下,用 Method.invoke() 触发行为,核心是“先获取类、再找方法、最后调用”,整个过程依赖反射机制。关键不在于硬编码类名,而在于通过可配置或动态传入的信息(如字符串类名、接口类型、注解标记等)定位目标类和方法。
通过类名字符串动态加载并调用
如果你只有类的全限定名(如 "com.example.ServiceImpl"),可以先用 Class.forName() 加载类,再通过反射获取实例和方法:
- 确保类在类路径中,且有无参构造函数(否则需用
getDeclaredConstructor().newInstance(...)) - 用
clazz.getDeclaredMethod("methodName", paramTypes...)获取方法,注意参数类型要精确匹配(如int.class不等于Integer.class) - 调用前建议
method.setAccessible(true),绕过 private/protected 访问限制 - 示例:Class> clazz = Class.forName("com.example.TaskRunner");
Object instance = clazz.getDeclaredConstructor().newInstance();
Method method = clazz.getMethod("execute", String.class);
method.invoke(instance, "hello");
基于接口或父类统一调用约定方法
若多个类实现同一接口(如 Runnable)或继承同一基类,可约定方法名(如 run()、handle()),避免硬编码类名:
- 从配置、SPI、Spring 容器或自定义扫描中获取实现了某接口的类实例列表
- 对每个实例,直接用
instance.getClass().getMethod("handle").invoke(instance) - 这样只需知道接口类型,无需关心具体实现类名;配合泛型或工厂模式更安全
借助注解自动发现并触发目标方法
用自定义注解(如 @AutoTrigger)标记待调用的方法,再通过类路径扫描找到所有含该注解的类和方法:
- 使用
org.reflections或 Spring 的ClassPathScanningCandidateComponentProvider扫描带注解的类 - 遍历结果,对每个匹配的
Method对象调用invoke,传入其所在类的新实例 - 适合插件化、事件驱动场景,例如:标注
@OnStartup的方法在应用启动时自动执行
处理常见异常与安全边界
invoke 调用容易抛出多种异常,需针对性处理:
-
ClassNotFoundException:检查类名拼写、包路径、JAR 是否在 classpath -
NoSuchMethodException:确认方法名、参数个数与类型完全一致(可用getMethods()打印调试) -
IllegalAccessException:调用setAccessible(true)开放访问 -
InvocationTargetException:这是包装了目标方法内部异常的壳,用e.getCause()获取原始错误 - 生产环境慎用反射调用敏感方法(如含用户输入的类名),防止任意代码执行风险











