桥接方法仅在实际提供新方法实现的类上生成,不随继承深度累积。例如a→b→c中,仅c重写get()时只为c生成桥接;若b和c均重写,则b生成桥接而c不生成,因c与b擦除后签名一致。

多层继承链中同一泛型方法被多次重写时,桥接方法不是按“层数”逐级生成的,而是由编译器针对每个具体实现类,在它与直接父类型擦除后的方法签名不匹配时,单独生成一个桥接方法。它不跨层传递,也不叠加嵌套,只解决本层重写语义到字节码层面的落地问题。
桥接方法只在“实际实现类”上生成,不随继承深度累积
假设存在三层泛型继承链:
A
其中 A 声明 public T get(),B 未重写(仅继承),C 重写为 public String get()。
- A 擦除后:Object get()
- B 未重写,无新方法体,不生成桥接方法
- C 实际实现了 String get(),而其直接父类 B 擦除后签名仍是 Object get() → 签名不一致 → 编译器只为 C 生成一个桥接方法:
public Object get() { return (String) this.get(); }
不会因为 A→B→C 有三层,就在 B 上也生成桥接方法;B 没有提供新的方法实现,就不是桥接方法的生成主体。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
中间层重写会触发独立桥接,但彼此互不影响
若改为:
A
- A
擦除后:Object get() - B 重写为 String get() → 与 A 擦除签名不匹配 → 编译器为 B 生成桥接:
public Object get() { return this.get(); } - C 重写的是 B 的方法(源码中重写的是 String get()),而 B 擦除后对外暴露的是 Object get() 和 String get() 两个方法(后者是真实方法,前者是桥接)→ C 的 String get() 与 B 的 String get() 签名一致 → 不触发新桥接
- 最终只有 B 类含桥接方法,C 类没有额外桥接
返回类型协变 + 泛型擦除共同作用时仍只生成一个桥接
例如:abstract class Box<t> { abstract T get(); }</t>class IntBox extends Box<integer> { @Override public Integer get() { return 42; } }</integer>class SignedIntBox extends IntBox { @Override public Integer get() { return -42; } }
- Box 擦除后:Object get()
- IntBox 提供了 Integer get() → 与 Object get() 不一致 → 生成桥接方法
- SignedIntBox 重写的是 IntBox 的 Integer get(),签名完全一致 → 无桥接
- 即使 SignedIntBox 也声明为
extends Box<number></number>并试图返回 Number,只要其方法签名与直接父类擦除后签名匹配,就不新增桥接
如何验证桥接方法是否生成及归属
- 用
javap -v 类名查看字节码,搜索ACC_BRIDGE标志,注意观察SourceFile和declaring class - 反射获取所有声明方法:
clazz.getDeclaredMethods(),再调用method.isBridge()判定 - 关键看
method.getDeclaringClass()—— 桥接方法永远属于它所“补全”的那个具体实现类,而非祖先类 - 不要依赖 IDE 的“Find Usages”或跳转逻辑判断桥接存在,它们通常过滤掉 synthetic 方法;必须查字节码或反射结果
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










