桥接方法是编译器为泛型擦除后签名不匹配生成的转发方法,不影响@ override判定;重写判定仅基于泛型擦除前的源码签名,包括方法名、参数类型(含泛型形参)、顺序及返回类型协变关系。

桥接方法不影响你写代码时对重写的判断,但会悄悄改变字节码里的方法结构。关键在于:@Override 只认源码签名,编译器生成桥接方法是“事后补救”,不是重写判定的依据。
重写判定只发生在泛型擦除前的语义层
Java 编译器检查 @Override 时,根本没看字节码,也不管有没有桥接方法。它只比对你写的源码是否满足以下条件:
- 方法名、参数个数、顺序完全一致
- 参数类型(含泛型形参)与父类方法声明严格匹配,比如父类是
<t extends user> T load(T id)</t>,子类必须也写<t extends user> T load(T id)</t>,不能只写User load(User id) - 返回类型兼容:支持协变(子类可返回更具体的类型),但必须在源码中显式体现类型关系
桥接方法是编译器为运行时多态兜底的“中间转发者”
当你正确写出重写方法后,编译器发现擦除后签名不匹配(比如父类方法签名为 Object get(int),而你写的是 String get(int)),就会自动生成一个桥接方法来衔接:
- 桥接方法签名和父类原始方法一致(如
public Object get(int)) - 方法体只做一件事:强制类型转换 + 调用你手写的那个真实方法(如
return (String) this.get(i);) - 它被标记为
ACC_BRIDGE | ACC_SYNTHETIC,源码不可见,也不能加 @Override
实战观察:用 javap 看清桥接方法的存在
写一个典型例子,比如继承 AbstractList<string></string> 并重写 get(int):
- 编译:
javac MyList.java - 反编译:
javap -c -v MyList - 查找带
ACC_BRIDGE标志的方法,你会看到类似:
descriptor: (I)Ljava/lang/Object;
flags: (0x0041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
这个就是编译器为你织入的桥接代码——它不参与 @Override 判定,但确保 JVM 在多态调用 List.get() 时能正确落到你的 String get(int) 上。
常见误判场景与避坑点
以下写法看似合理,但加 @Override 会直接报错,和桥接方法无关:
- 父类定义
void process(List<string> list)</string>,子类写@Override void process(List<integer> list)</integer>→ 泛型实参不同,不构成重写 - 父类是
Base<t></t>,子类继承为Child extends Base<string></string>,然后重写handle(String s)却没带<t></t>声明 → 源码签名不匹配 - 反射时用
getDeclaredMethod("get", int.class)拿到的是桥接方法,若误当业务方法调用并强转返回值,会抛ClassCastException










