桥接方法是编译器为修复泛型擦除导致的重写断裂而自动生成的转发方法,签名与父类擦除后一致,仅做类型转换并调用子类真实方法,带ACC_BRIDGE和ACC_SYNTHETIC标志,确保JVM动态分派正确走向子类逻辑。

Java泛型擦除后,方法重写(override)可能失效,但重载(overload)不受影响;桥接方法(Bridge Method)是编译器为修复重写断裂而自动生成的转发方法,只出现在继承/实现关系中签名因擦除不匹配的场景,与重载无关。
桥接方法只解决重写断裂,不参与重载解析
泛型擦除导致父类/接口方法签名在字节码层面变为原始类型(如 T → Object),而子类用具体类型重写(如 String get())时,JVM 无法识别为合法重写——因为方法名相同、参数相同但返回类型或参数类型不一致。此时编译器插入桥接方法来“补位”,让 invokevirtual 调用能正确分派到子类逻辑。
重载则完全不同:它依赖编译期静态解析,看的是源码中方法声明的完整签名(含实际参数类型)。擦除不影响重载判定,也不会触发桥接方法生成。例如:
-
void process(String s)和void process(Integer i)擦除后都是process(Object)→ 编译报错(签名冲突),不是重载成功 -
void handle(List<String>)和void handle(List<Integer>)擦除后都是handle(List)→ 同样冲突,无法共存
桥接方法生成的典型场景
以下三类情况会触发编译器自动插入桥接方法:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
-
返回类型协变:父类定义
<T> T getValue(),子类写String getValue()→ 擦除后父类为Object getValue(),子类为String getValue()→ 不匹配 → 生成public Object getValue() { return this.getStringValue(); } -
参数类型窄化:父类定义
<T> void set(T value),子类写void set(String value)→ 擦除后父类为void set(Object),子类为void set(String)→ 不匹配 → 生成public void set(Object obj) { this.setString((String) obj); } -
实现泛型接口的默认方法:接口有
default <T> void accept(T t)(擦除为accept(Object)),实现类写public void accept(String s)→ 编译器同样补桥接方法,确保通过接口引用调用时能命中
如何确认桥接方法是否存在
桥接方法不会出现在源码中,也不接受 @Override 标注,只能通过字节码或反射验证:
- 用
javap -v YourClass.class查看,找到带有ACC_BRIDGE和ACC_SYNTHETIC标志的方法,其 descriptor 会显示擦除后的签名(如(Ljava/lang/Object;)V) - 用反射遍历方法:
method.isBridge()返回true即为桥接方法 - 注意:桥接方法体极简,仅做类型转换+委托调用,无业务逻辑
桥接方法不是重载,也不能被重载
桥接方法由编译器合成,不可见、不可继承、不可覆盖。它不参与重载决议——即使你手动声明一个同名同参的方法,也不会和桥接方法构成重载;JVM 只把它当作重写链中的适配入口。若子类自己再声明一个与桥接方法签名相同的普通方法(如也写 public Object get()),编译会报错(重复方法定义)。
本质上,桥接方法是编译器对“源码语义”和“字节码契约”之间落差的自动弥合,不是语言特性,而是实现细节。理解它,就能看清泛型多态在运行时真实靠什么支撑。

















