多态通过继承、重写和父类引用指向子类对象实现运行时动态绑定,解决行为抽象与扩展问题;反射则在运行时动态获取类信息并调用任意成员,用于方法名未知、私有方法调用等多态无法覆盖的场景。

多态本身不直接“配合”反射,而是两者解决不同层面的问题:多态让父类引用能自动调用子类重写的方法,属于编译期约定、运行时绑定;反射则绕过编译期约束,在运行时强行访问任意类的任意成员。真正需要“动态调用未知子类方法”时,往往是多态无法覆盖的场景——比如方法名在运行时才确定、子类未重写父类方法、或需调用私有/新增方法。这时反射才真正介入。
多态能解决的,优先用多态
如果目标只是让父类逻辑触发子类定制行为,标准多态就足够了:
- 定义抽象方法或默认方法(如
protected abstract void doWork()) - 子类必须实现该方法,否则编译不通过
- 父类中统一调用
this.doWork(),JVM 自动分派到实际子类实现
这种方式安全、高效、类型清晰,无需反射。它依赖的是继承 + 重写 + 向上转型,是面向对象设计的基石。
反射补足多态做不到的事
当遇到以下情况,才需要反射介入:
- 子类有某个特定方法(如
backupData()),但父类没声明也没要求实现 - 方法名来自配置文件、用户输入或外部协议(如字符串
"initConfig") - 要调用子类的私有方法或未暴露给父类接口的扩展方法
- 框架需兼容未来可能新增的子类,且不修改现有父类代码
此时反射不是替代多态,而是延伸能力边界。典型做法是:先用多态获得子类实例,再用反射调用其专属方法。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
安全调用子类方法的反射步骤
以父类持有子类实例为前提,动态调用其任意方法(含私有):
- 获取子类 Class 对象:
Class extends Parent> cls = obj.getClass() - 查找目标方法(注意参数类型匹配):
Method m = cls.getDeclaredMethod("methodName", String.class, int.class) - 若为私有方法,放开访问:
m.setAccessible(true) - 执行调用:
m.invoke(obj, "arg1", 123) - 捕获并处理
IllegalAccessException、InvocationTargetException等异常
关键点在于:反射操作的是具体实例的运行时类型,而非引用类型。所以即使变量声明为 Parent p = new ChildA(),p.getClass() 返回的仍是 ChildA.class,能准确找到子类独有的方法。
避免滥用反射的实用建议
反射灵活但代价明显,日常开发中应守住底线:
- 不用反射替代本可用多态解决的问题(如简单的行为差异)
- 避免在高频路径(如循环体、IO处理)中反复反射获取 Method,可缓存 Method 实例
- 调用前校验方法是否存在、参数是否匹配,而不是全靠异常兜底
- JDK 9+ 模块系统下,需显式开放包权限(
add-opens),否则setAccessible(true)可能失败
本质上,多态负责“结构契约”,反射负责“运行时探查”。一个管该做什么,一个管怎么做——二者各司其职,组合使用时才真正强大。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










