java编译器为解决泛型擦除导致的重写签名不匹配问题,自动生成桥接方法:父类泛型方法擦除后为object签名,子类特化为string签名时,编译器插入public object get(object)桥接方法并委托调用子类get(string),该方法带acc_bridge标志,是jvm实现多态的关键。

Java 编译器在子类重写父类泛型方法时,若父类方法经类型擦除后签名与子类实际方法不一致(比如参数或返回类型因泛型特化而不同),就会自动生成桥接方法来“补全”重写关系。这种桥接不是你写的,但真实存在于字节码中,是 JVM 正确执行多态的关键。
桥接方法出现的典型场景
当父类定义的是泛型方法,而子类继承时指定了具体类型,并重写了该方法——但擦除后父类方法签名变成原始类型(如 Object),而子类方法签名仍是具体类型(如 String)时,JVM 无法直接认定这是重写。此时编译器插入一个桥接方法,签名与父类擦除后一致,内部调用你的实际方法。
- 父类泛型方法:
public abstract T get(T t)→ 擦除为public abstract Object get(Object t) - 子类实现:
@Override public String get(String s)→ 签名不匹配擦除后的父类方法 - 编译器自动添加桥接方法:
public Object get(Object t),内部强转并调用get((String) t)
如何验证桥接方法存在
不能靠看源码,必须反编译字节码:
- 编译代码后,执行:
javap -v SubClass.class - 查找含
ACC_BRIDGE ACC_SYNTHETIC标志的方法(例如:public bridge synthetic java.lang.Object get(java.lang.Object)) - 用反射也可检测:
method.isBridge()返回 true 即为桥接方法
为什么不能绕过桥接直接调用?
因为 JVM 的方法重写规则只认签名(方法名 + 参数类型 + 返回类型),不认泛型信息。没有桥接方法,子类就无法满足父类抽象方法的契约,编译会失败;即使编译通过,运行时多态调用也会跳过子类方法,导致逻辑错误。
- 例如:
SuperClass<string> obj = new SubClass(); obj.get("x");</string>—— 实际触发的是桥接方法,再委托给你写的get(String) - 若手动删掉桥接方法(如用字节码工具),该调用将抛
AbstractMethodError或走错路径
实战建议:写代码时注意什么
你无需也不应手动编写桥接方法,但需理解它何时出现、为何存在,才能写出可预期的泛型继承结构:
- 避免在子类中声明与父类擦除后签名冲突的同名方法(如同时存在
process(Object)和process(String)) - 使用 IDE 的字节码查看插件(如 IntelliJ 的 “Show Bytecode”)快速确认桥接是否生成
- 在反射遍历方法时,过滤掉
isBridge() || isSynthetic()的方法,防止误处理 - 单元测试中,尽量用父类/接口引用调用,而非子类引用,才能真实触发桥接逻辑











