桥接方法是编译器为解决泛型类型擦除与多态性冲突自动生成的适配层,它通过生成签名匹配父类擦除后方法、内部强制转换调用子类真实方法的bridge method,保障@override语义正确性和运行时多态调用。

桥接方法是编译器为解决泛型类型擦除与面向对象多态性之间天然矛盾而自动生成的“适配层”。它不需手动编写,却在字节码层面默默保障了 @Override 的语义正确性——看似重写的泛型方法,实际靠桥接方法完成运行时调用转发。
为什么需要桥接方法?类型擦除破坏了重写契约
Java 泛型仅存在于编译期。一旦进入字节码,所有泛型参数都会被擦除:
-
无界泛型
<t></t>→ 擦除为Object -
有界泛型
<t extends number></t>→ 擦除为Number -
通配符
? super String→ 擦除为Object
例如,Pair<date></date> 编译后等价于原始类 Pair,其方法签名变为:
public Object getValue()public void setValue(Object value)
而子类 DateInter extends Pair<date></date> 中显式重写的:
@Override public Date getValue()@Override public void setValue(Date value)
在擦除后,父类方法参数是 Object,子类方法参数是 Date —— 这已不符合“方法名相同 + 参数类型相同”的重写定义,本应是重载。但 Java 要求多态必须成立(比如用 Pair<date> p = new DateInter()</date> 后能正常调用),于是编译器介入补位。
桥接方法怎么生成?编译器自动插入转发逻辑
当检测到子类方法因泛型擦除导致签名与父类不匹配但仍标注 @Override 时,编译器会在子类字节码中合成一个桥接方法(bridge method),特征为:
- 方法名和参数类型与父类擦除后一致(如
setValue(Object)) - 方法体只做一件事:强制类型转换后委托给子类真实方法(如
setValue((Date) obj)) - 字节码中标记为
ACC_BRIDGE | ACC_SYNTHETIC
以 setValue(Date) 为例,编译器生成的桥接方法形如:
public void setValue(Object obj) { setValue((Date) obj); }
这样,当通过父类引用调用 setValue(new Date()) 或 setValue(new Object())(后者会抛 ClassCastException)时,JVM 总能找到匹配的入口,且语义仍由子类逻辑主导。
如何验证桥接方法存在?用 javap 查看字节码签名
源码无法体现桥接方法,必须检查编译后的字节码:
- 执行
javac DateInter.java - 执行
javap -c -v DateInter - 查找含
bridge和synthetic标记的方法 - 对比 descriptor(如
(Ljava/util/Date;)Vvs(Ljava/lang/Object;)V)确认签名差异
若看到两个 setValue 方法共存,且其中一个 descriptor 参数为 Object、另一个为 Date,就说明桥接已生效。
桥接方法也用于协变返回类型场景
不只是泛型,任何返回类型更具体的重写都会触发桥接。例如:
class Animal {}class Dog extends Animal {}class Base { Animal get() { return new Animal(); } }class Sub extends Base { @Override Dog get() { return new Dog(); } }
此时编译器同样生成桥接方法:Animal get() { return (Animal)get(); },确保父类引用调用时仍可返回 Animal 类型,同时保留子类精确返回能力。










