方法重载匹配分三阶段:第一阶段严格精确匹配;第二阶段允许安全数值提升;第三阶段启用装箱/拆箱与可变参数。不比较“相似度”,多解即报错。

方法重载的参数类型匹配不是“找最像的那个”,而是按**严格、确定、分阶段**的规则走,Java 和 C# 等主流语言都遵循类似逻辑(以 Java 为准说明)。
第一阶段:只考虑基本类型和装箱/拆箱前的原始类型
编译器先尝试在不使用任何隐式类型转换(比如 int → long)、不触发自动装箱(int → Integer)、不触发拆箱(Integer → int)、也不走可变参数(...args)的前提下,找到完全匹配的方法。
- 例如:有
void f(int x)和void f(double x),调用f(5)→ 匹配f(int) - 调用
f(5L)→ 匹配f(double)?不,long不等于double,但long可以 直接提升为double—— 这属于第二阶段
第二阶段:允许扩展的原始类型转换(widening primitive conversion)
如果第一阶段没找到,就允许以下安全的、不会丢失精度的数值提升:
-
byte,short,char→int -
int→long→float→double -
char→int→long等(但char不直接转long,是经int中转)
注意:float 不会自动转成 double 的重载方法(虽然语法允许),但这是 widening,所以 f(float) 和 f(double) 同时存在时,f(3.14f) 一定选 f(float);而 f(3.14)(字面量是 double)只能匹配 f(double)。
第三阶段:允许装箱、拆箱和可变参数
前两阶段都没匹配上,才启用更“宽松”的规则:
- 把基本类型自动装箱(
int → Integer),或把包装类拆箱(Integer → int) - 把实参适配到
T...形参(比如传一个int给void f(Integer...),会先装箱再当单元素数组) - 但注意:装箱 + 可变参数 是最低优先级,且不能同时发生多层转换(比如
byte → Integer...就不合法)
关键细节:不找“最优”,只找“唯一可接受”的
编译器不会比较“哪个更接近”,只要多个方法在某阶段都“可行”,就报错(ambiguous):
- 有
f(Object x)和f(String x),调用f(null)→ 编译失败,因为两个都匹配第三阶段(null可赋给任意引用类型) - 有
f(int x)和f(long x),调用f(10)→ 选int(第一阶段精确匹配),不会因为long“范围更大”就选它










