第 52 条:慎用重载
重载是编译时静态绑定,重写是运行时动态绑定;二者行为差异巨大,极易引发隐蔽 bug,因此必须慎用、少用、优先用不同方法名。
重载和重写的使用区别
- 重载(Overloading):同一类中,方法名相同、参数列表不同
绑定时机:编译时就确定调用哪个方法(看参数的编译时类型)
多态性:无,不支持动态分发
典型场景:构造器、工具类(如 String.valueOf) - 重写(Overriding):子类重写父类方法,签名完全一致
绑定时机:运行时确定调用哪个方法(看对象的运行时类型)
多态性:有,符合面向对象预期
典型场景:接口实现、子类扩展
核心点:重载是的选择是静态的,在编译时选择,而覆盖方法是动态的,根据运行时对象选择。所以重载不太符合我们的常理习惯。
例如:
一个看似可以判断集合类型的方法。
java
public class Main {
// 重载1:Set
public static String classify(Set<?> s) { return "Set"; }
// 重载2:List
public static String classify(List<?> lst) { return "List"; }
// 重载3:Collection(父类)
public static String classify(Collection<?> c) { return "Unknown Collection"; }
public static void main(String[] args) {
// 编译时类型都是Collection<?>
Collection<?>[] collections = {
new HashSet<>(), // 运行时Set
new ArrayList<>(), // 运行时List
new HashMap<>().values()
};
for (Collection<?> c : collections) {
// 编译时只认Collection,永远调用第3个重载
System.out.println(classify(c));
}
}
}

输出了三次Unknown Collection,因为在编译时类型都是Collection<?>。
想要解决,可以通过在方法中添加instanceof显式判断类型。
java
public static String classify(Collection<?> c) {
if (c instanceof Set) return "Set";
if (c instanceof List) return "List";
return "Unknown Collection";
}
重载使用规则
因为重载会有以上的问题,所以在使用重载时,要设计合理,让调用者方便的分辨和调用,重要的是符合调用者的预期。
- 保守策略:避免相同参数个数的重载
- 最优:不用重载,用不同方法名(如writeInt()/writeBoolean())
- 次优:参数个数必须不同(编译器一眼区分,无歧义)
- 若必须重载:参数类型需 "本质不同"
- 安全:参数类型无继承关系、不能互相强转(如int vs String、List vs Map)
- 危险:参数存在父子类关系(如Collection vs Set)------ 极易触发静态绑定陷阱
- 构造器重载:优先用静态工厂方法
- 构造器必须同名,重载不可避免时:
- 保证参数个数不同
- 或参数类型本质不同
- 更优:用静态工厂(如List.of()/Collections.emptyList()),方法名可表达语义
- 函数式接口重载:绝对禁止
- 同一位置参数用不同函数式接口(如Runnable vs Callable),编译器无法区分,直接编译失败。
- 重载方法行为必须一致
- 若多个重载最终做同一件事,可通过转发调用保证行为统一:
java
public boolean contentEquals(StringBuffer sb) {
return contentEquals((CharSequence) sb); // 转发到通用方法
}
- 这样程序员虽然可能并不知道哪个重载函数会被调用,但只要这两个方法返回相同的结果就行。
书中反例:
java
public static String valueOf(char[] data)
public static String valueOf(Object obj)
传入char[]时,两个方法都匹配
但行为完全不同:
- valueOf(char[]):直接转字符串内容
- valueOf(Object):调用toString()(数组默认输出哈希码)
不过不想多的话其实还是挺符合直觉的,优先精确匹配。
总结
参数个数相同的方法尽量别重载;构造器因语法限制没法避免重载时,绝不能设计出同一参数可自动类型转换适配多个重载的情况;若因兼容改造实在避不开,必须保证传入相同参数时,所有重载行为完全一致,否则会因重载静态绑定特性造成行为错乱、难以排查理解。