Java字节码/类格式下方法重写判定规则及调用生效场景咨询
JVM字节码层面方法重写的判定规则
核心判定条件
JVM进行虚方法(invokevirtual、invokeinterface指令调用的方法)分派时,判断子类方法是否重写父类方法的唯一硬性标准是:
- 子类方法为非私有、非静态
- 父类方法为非私有、非静态、非final
- 两者方法名称完全一致
- 两者方法描述符完全一致:JVM的方法描述符包含完整的参数类型列表和返回值类型,也就是说仅参数相同、返回值不同的两个方法,在字节码层面属于完全独立的方法,不会被判定为重写。
你提到的“参数相同、返回值为父类方法返回值子类型”的场景,要实现重写语义,必须依赖额外的桥接方法:编译器会在子类中自动生成一个和父类方法名称、描述符完全一致的桥接方法,该方法内部转发调用子类中返回值为子类型的具体实现,此时调用父类方法就会先走到桥接方法,再执行子类的实际实现,对外表现为子类重写了父类方法。
反射场景的判断方法
如果通过反射判定重写关系,不能仅比对方法名和参数类型,需要做以下校验:
- 先检查子类中是否存在和父类方法名称、参数类型、返回值类型完全一致的方法,若存在则构成重写
- 若不存在,则检查子类中是否存在对应名称和参数类型、返回值为父类返回值子类型的方法,同时存在对应桥接方法(可通过
Method.isBridge()判断),则也属于有效重写,触发虚分派时会执行子类实现。
跨场景适用性
上述规则是JVM规范明确定义的,对所有运行在JVM上的场景都生效:
- 其他编译为JVM字节码的语言(Scala、Kotlin等)均遵循该规则,比如你提到的Scala中
Map的map方法,类型擦除后Map的map返回值为Map,和父类Iterable的返回值Iterable不匹配,Scala编译器会自动生成对应的桥接方法实现重写语义 - 运行时代码生成场景(ASM、CGLIB动态代理等)生成的字节码,只要符合上述重写规则,就会走正常的虚方法分派
- Lambda转发器、函数式接口合成类等JVM自动生成的类,同样适用该规则。
内容的提问来源于stack exchange,提问作者Turin
相关产品推荐
相关产品推荐

