反编译Scala代码疑问:派生类为何存在两个重写方法?
为什么反编译B类会看到两个m1方法?
嘿,这个问题本质是Java泛型的类型擦除机制在搞事情,我给你拆解明白:
首先先还原一下你大概率遇到的代码场景(毕竟泛型才会触发这个现象):
假设你的A类是带泛型的父类,B是它的子类:
// 父类A,带泛型参数T public class A<T> { public T m1(T t) { return t; } } // 子类B,指定泛型为String并重写m1 public class B extends A<String> { @Override public String m1(String s) { return s.toUpperCase(); } }
核心原因:类型擦除+桥接方法
Java的泛型是编译时特性,编译后泛型信息会被擦除:
- 父类A的泛型
T会被擦除成最接近的上限类型(这里就是Object),所以编译后的A类里,m1方法的签名变成了public Object m1(Object t)。 - 而你在B类里写的
m1方法,签名是public String m1(String s)——这和擦除后的父类方法签名其实不一样!
那问题来了:如果没有特殊处理,当我们用父类引用指向子类对象时(比如A<String> a = new B(); a.m1("hello");),JVM会根据擦除后的方法签名Object m1(Object)去B类里找,但B里只有String m1(String),多态就失效了。
为了避免这个问题,Java编译器会自动在B类中生成一个桥接方法,也就是你看到的那个public java.lang.Object m1(java.lang.Object)方法。它的内部逻辑很简单,就是把参数强转成String后调用你写的String m1(String)方法,相当于一个“中转层”,保证多态机制正常运行。
额外验证
你可以看看反编译后的B类代码,这个自动生成的桥接方法会带有synthetic(合成的)标记,说明它不是你手动写的,是编译器为了兼容机制加的。
简单来说:这个额外的方法不是A类的方法跑到B里了,而是编译器为了处理泛型擦除和多态兼容自动生成的桥接方法,属于完全正常的现象~
内容的提问来源于stack exchange,提问作者CodingNow
相关产品推荐
相关产品推荐

