桥接方法是编译器为满足JVM泛型擦除后字节码契约而自动生成的转发方法,需通过method.isBridge()识别并过滤,避免干扰业务逻辑或引发类型转换异常。

反射访问桥接方法,核心不是“怎么调用它”,而是“为什么要识别并跳过它”。桥接方法是编译器悄悄生成的辅助代码,不是你写的逻辑,也不该参与业务处理——比如 MyBatis 反射扫描方法时,就用 !method.isBridge() 过滤掉它们。
桥接方法是怎么来的
Java 泛型在编译期被擦除,但 JVM 要求子类必须完整实现父接口/父类的字节码签名。例如:
- 接口
IHello<T>声明了void sayHello(T t),擦除后变成void sayHello(Object t); - 实现类
HelloWorld显式写的是void sayHello(String s); - 编译器自动补上一个
void sayHello(Object o) { sayHello((String)o); }——这就是桥接方法。
它让 JVM 看起来“实现了接口”,实际执行仍走你写的那个类型精确的方法。
怎么识别桥接方法
反射中判断非常直接:
-
method.isBridge()返回 true → 是桥接方法; - 对应字节码标记为
ACC_BRIDGE | ACC_SYNTHETIC(即同时具备桥接和合成属性); - 它通常参数更宽泛(如
Object)、返回值更泛化(如Object),且方法体只做类型转换和转发。
注意:getMethods() 默认不返回桥接方法,但 getDeclaredMethods() 会——所以实际框架里常用后者 + isBridge() 过滤。
为什么不能直接调用桥接方法
它不是设计给开发者调用的,强行调用可能引发意外行为:
- 参数类型不匹配:传
Integer给sayHello(Object)桥接方法,内部强转成String会抛ClassCastException; - 语义失真:它只是转发壳,绕过它才能命中你真正实现的逻辑分支;
- 框架约定:Spring、MyBatis 等均默认忽略桥接方法,若你手动保留,可能破坏其方法解析逻辑(如 HandlerMethod 匹配失败)。
实用建议
日常开发中遇到反射获取方法,按这个顺序处理更稳妥:
- 优先用
getDeclaredMethods()获取全部声明方法; - 过滤掉桥接方法:
!m.isBridge(); - 再过滤掉合成方法(如 lambda 生成的):
!m.isSynthetic(); - 最后按需筛选 public / 参数类型 / 注解等业务条件。
这样既符合 JVM 规范,也与主流框架行为一致,避免因桥接方法干扰导致的运行时异常或逻辑错位。

















