重载方法必须在同一个类中定义,判断依据仅为参数列表(数量、类型、顺序),与返回值无关;调用在编译期按变量声明类型绑定,不跨类追溯,泛型擦除可能引发重载冲突。

重载方法必须在同一个类里定义
Java 的重载只发生在单个类的内部,不是父子类之间的事。你不能靠继承另一个类里的方法,再在子类里写个参数不同的同名方法就叫重载——那只是子类自己的新方法,和父类方法没重载关系。
常见错误现象:javac 不报错,但调用时总走父类方法,或者 IDE 提示“method is never used”,其实是没理解重载生效范围。
- 重载判断只看**声明该方法的类**,不跨类追溯
- 子类中定义
void print(String s),父类有void print(Object o),两者不构成重载关系(它们属于不同类) - 想让子类也支持多种参数,得在子类里把所有重载版本都重新写一遍
参数列表必须不同,返回值类型无关
重载的唯一判断依据是参数的数量、类型或顺序不同;return 类型完全不影响是否重载。哪怕两个方法仅返回值不同,其余一模一样,编译器直接报错:method xxx() is already defined in class YYY。
容易踩的坑:以为 int getId() 和 String getId() 能共存,实际根本通不过编译。
立即学习“Java免费学习笔记(深入)”;
- 合法差异:
get(String id)vsget(long id)vsget(String id, boolean cache) - 非法差异:
String getName()vsint getName()(编译失败) - 注意基本类型和包装类:
setValue(int x)和setValue(Integer x)是两个独立重载版本,但自动装箱可能引发调用歧义
编译期绑定决定调用哪个重载版本
重载方法的选择发生在编译阶段,依据的是**变量声明类型**,而不是运行时实际对象类型。这点和重写(Override)截然相反,也是最容易混淆的地方。
典型场景:用父类引用指向子类对象,再调用重载方法,结果往往不符合直觉。
-
Object obj = new String("abc");然后调用print(obj),选的是print(Object o),不是print(String s) - 即使
obj实际是String,只要声明类型是Object,编译器就只考虑Object及其父类能匹配的重载版本 - 如果想触发更具体的重载,得显式转型:
print((String) obj),但这要确保类型安全,否则运行时报ClassCastException
泛型方法和重载一起用要格外小心
泛型擦除会让某些看似不同的签名在编译后变成一样的字节码,导致重载冲突。这不是 bug,是 Java 类型系统的限制。
比如 <T> void handle(List<T> list) 和 void handle(List<String> list) 看似不同,但擦除后都是 handle(List list),编译直接失败。
- 泛型方法的形参类型在擦除后若与其他方法签名重复,就会报
method xxx has the same erasure as another method - 解决办法:避免对泛型集合做具体类型的重载;改用不同方法名,比如
handleAnyList(List list)和handleStringList(List<String> list) - 如果真需要区分,可用桥接方法 + @SuppressWarnings("unchecked"),但代价是可读性和维护性下降








