发布于2026-07-03 阅读(0)
扫一扫,手机访问
Ja va反射调用多态方法时,**不会绕过多态分派机制**,而是严格遵循JVM的动态分派规则——即仍以对象的**实际类型(runtime type)** 为依据,查找并执行重写后的方法。反射本身不改变分派逻辑,它只是换了一种方式触发 invokevirtual 指令。

invokevirtual通过 Method.invoke(obj, args) 调用一个非静态、非私有、非构造器的方法时,JVM底层仍使用 invokevirtual 指令(对普通类)或 invokeinterface(对接口),而非直接跳转到某个具体实现。这意味着:
Method 对象声明的参数类型(即“静态类型”)决定,而是由传入的 obj 实际指向的实例类型决定;clazz.getMethod("foo", String.class) 从父类 Parent.class 获取方法,只要 obj 是 Child 实例且 Child 重写了 foo,最终执行的就是 Child.foo();Method 的过程只影响“找方法签名”的阶段(编译期/加载期解析),不干预运行时方法绑定。JVM在执行 invoke 前会做两件事:
obj 是否为 null(空指针异常);obj 的实际类元数据(即 obj.getClass() 返回的 Class 对象),并以此为起点,在其方法表(vtable)中按方法签名查找可执行版本;Object;若仍未找到,抛出 IllegalAccessException 或 IllegalArgumentException(取决于访问控制与签名匹配)。这个查找路径与普通代码中 obj.foo() 完全一致——区别仅在于:普通调用由编译器生成符号引用 + 运行时动态链接;反射调用由 Method 对象携带符号信息 + 运行时即时解析链接。
重载是**静态分派**,依赖参数的**静态类型**,而反射调用时参数类型已固化为 Object[],编译器无法参与重载选择:
method.invoke(obj, "hello") 中的 "hello" 是 String 实例,但反射层只把它当作 Object 传入,不参与重载决议;getMethod(...) 或 getDeclaredMethod(...) 时传入的 Class>... 参数——这一步发生在调用前,属于开发者手动指定,而非JVM自动分派;Method 阶段(静态),而“方法执行”阶段只有动态分派(重写)。当反射调用一个接口方法(如 List.size())时:
invokeinterface 指令;obj 的实际类型查找实现类中的对应方法;invokevirtual,但语义不变。例如:Method m = List.class.getMethod("size"); m.invoke(new ArrayList()) 最终执行的是 ArrayList.size(),而非 List 接口的默认方法(除非 ArrayList 没提供实现且接口有 default 方法)。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8