关键在于jvm编译后签名:泛型擦除使list和list均变为list,导致同名同签名冲突;用javap -s验证descriptor是否重复;桥接方法可能与手动方法重叠;应改用语义化命名如parsestrings()避免冲突。

排查这类问题,关键不在源码表面写法,而在于看清编译后 JVM 实际认什么签名。类型擦除会让不同泛型参数的方法“坍缩”成同一个字节码签名,JVM 严格禁止同名、同参数类型、同返回类型的方法共存——冲突就在这里爆发。
看擦除后的参数类型是否真不同
别凭直觉判断 List
void handle(List<string> data)</string>void handle(List<boolean> data)</boolean>
因为擦除后都是 handle(List),JVM 看不出区别。
用 javap 验证字节码签名
不靠猜,直接看编译结果:
- 先执行
javac YourClass.java - 再运行
javap -s YourClass(-s显示签名描述符)
重点关注输出中形如 descriptor: (Ljava/util/List;)V 的行。如果两个方法的 descriptor 完全一致,说明 JVM 层面已无法区分,编译报错是确定行为。
检查桥接方法是否意外叠加
继承泛型类或实现泛型接口时,编译器会自动生成带 bridge 和 synthetic 标记的桥接方法。例如:
- 父类定义
<t> void process(T t)</t> - 子类覆写为
void process(String s) - 编译器会生成一个
process(Object)桥接方法
此时若你又手动写了另一个 void process(Object),就会和桥接方法签名重叠。用 javap -c -v YourClass 查看全部方法,确认是否有重复的 bridge 方法与你写的普通方法撞车。
改用语义化命名替代泛型重载
与其在擦除后“挤”同一个方法名,不如让名字说话:
- ❌
parse(List<string>)</string>/parse(List<integer>)</integer> - ✅
parseStrings(List<string>)</string>/parseNumbers(List<integer>)</integer>
逻辑相似时,可把共用部分抽成私有方法,由语义化方法分别调用。这既避开擦除冲突,也提升可读性和维护性。










