一个方法同时有固定参数版本和可变参数版本,调用时编译器怎么选?真实构造几组调用,把 JLS 里"三阶段重载解析"这条抽象规则变成具体、可验证的结果。
上一篇:Optional 本身可以是 null:真实验证这个类型没能真正杜绝 NPE
同时定义 pick(int a, int b) 和 pick(int... nums),两个版本理论上都能接受两个 int 参数的调用。
VarargsOverloadDemo.java static String pick(int a, int b) { return "固定两个参数版本"; } static String pick(int... nums) { return "可变参数版本,收到 " + nums.length + " 个"; }
pick(1, 2) 真实选中 = 固定两个参数版本 pick(1, 2, 3) 真实选中 = 可变参数版本,收到 3 个 pick(1) 真实选中 = 可变参数版本,收到 1 个 pick() 真实选中 = 可变参数版本,收到 0 个
真实结果验证了 JLS 重载解析的分阶段规则:pick(1, 2) 真实选中了固定参数版本,不是可变参数版本;而参数个数不是 2(1 个、3 个、0 个)的调用,固定版本压根不适用,编译器才真实落到可变参数版本上。
固定参数版本比可变参数版本优先级更高,不只是体现在参数个数上,类型匹配也是如此。
VarargsOverloadDemo.java static String pick2(String s) { return "固定 String 版本"; } static String pick2(Object... args) { return "可变参数 Object... 版本,收到 " + args.length + " 个"; }
pick2("hello") 真实选中 = 固定 String 版本
pick2("a", "b") 真实选中 = 可变参数 Object... 版本,收到 2 个
调用 pick2("hello") 时,理论上两个重载版本都能接受这次调用(String 可以直接匹配 pick2(String),也可以被当成 Object... 里唯一的一个元素),但真实结果显示编译器优先选中了固定参数版本。这背后是 JLS 定义的三阶段重载解析流程:第一阶段(不允许装箱/拆箱、不允许可变参数)能找到唯一匹配就直接用;只有第一阶段完全找不到匹配方法,才会进入允许装箱拆箱的第二阶段;第二阶段还找不到,才会进入允许可变参数展开的第三阶段。可变参数方法永远是"最后的选择",不是和固定参数方法平起平坐地竞争。
数组和可变参数在调用点上是等价的语法糖,真实验证直接传一个数组不会产生"数组的数组"。
pick(arr) 真实选中 = 可变参数版本,收到 3 个
每一行都是真实运行这段代码得到的结果。