Java反射调用子类重写方法天然支持运行时多态,因Method.invoke()基于对象实际类型触发动态绑定。只需用子类实例调用父类声明的方法,JVM自动执行对应子类版本,无需手动判断或转型。

Java 多态在反射中调用子类重写方法,核心在于:**反射获取的是运行时对象的实际类型(即真实 class),而 Method.invoke() 本身天然支持多态分派**。你不需要手动判断类型或强制转型,只要用子类实例去调用父类声明的方法,JVM 会自动执行该实例所属子类的重写版本。
1. 反射调用本身尊重运行时多态
Method 对象可以来自父类、接口或任意祖先类型,但只要它被 用子类实例调用,JVM 就会在运行时查该实例的真实类型,并触发动态绑定(virtual method dispatch)——这和普通代码中 parentRef.doSomething() 的行为完全一致。
例如:
- 定义
Animal父类,有makeSound()方法; -
Dog和Cat继承它并各自重写makeSound(); - 用
Animal.class.getDeclaredMethod("makeSound")获取 Method; - 再用
dogInstance或catInstance调用method.invoke(dogInstance)—— 输出就是 “汪汪” 或 “喵喵”,无需 if-else 判断。
2. 关键操作步骤(安全且通用)
确保反射调用能正确触发多态,注意以下几点:
立即学习“Java免费学习笔记(深入)”;
-
Method 必须可访问:如果是 private 方法,需先调用
method.setAccessible(true); - 传入的 target 对象必须是实际子类实例(不能是 null,也不能是错误类型);
- 方法签名要匹配:即使重写,参数列表和返回值必须与父类方法一致(否则不是重写而是重载);
-
避免用 Class.getMethod() 查找私有方法:应使用
getDeclaredMethod()并设为 accessible。
3. 示例代码(简洁可运行)
class Animal { void makeSound() { System.out.println("Animal sound"); } }
class Dog extends Animal { void makeSound() { System.out.println("Woof!"); } }
class Cat extends Animal { void makeSound() { System.out.println("Meow!"); } }
public class ReflectPolymorphism {
public static void main(String[] args) throws Exception {
Animal dog = new Dog();
Animal cat = new Cat();
// 从父类获取方法(也可从 Object.class 等更上层获取)
Method m = Animal.class.getDeclaredMethod("makeSound");
m.invoke(dog); // 输出:Woof!
m.invoke(cat); // 输出:Meow!
}
}
4. 常见误区提醒
- 不是“反射实现多态”,而是“反射调用不破坏多态”——多态由 JVM 在 invoke 时自动保障;
- 不要试图用反射绕过访问控制来“模拟重写”:比如在父类里反射调用子类私有方法,这不是多态,是强行侵入;
-
泛型擦除不影响多态调用:List
和 List 的 get() 方法反射调用仍走各自实际类型逻辑(前提是它们真有不同实现,如自定义子类); - 若方法被
static修饰,则失去多态性——反射调用 static 方法只看 Method 所属 Class,与 target 实例无关。


















