调用哪个方法?(整数...a) vs. (int a, int b)

我刚刚发现了一个非常有趣的Java技巧:

void method1(Integer... a){
}

因此,您可以根据需要为此方法提供任意数量的整数。

现在,如果我有一个类似的(重载)方法,如下所示:

void method1(int a, int b){

}

当我执行以下行时,哪个方法运行:

method1(1, 2);

好吧,我可以通过使用不同的方法指令进行测试来非常容易地发现这一点,但是当我考虑“重载”方法中的“规则”时,我必须确保每个重载方法都必须相同,以便编译器确切地知道要使用哪一个。

在我看来,上面的代码不应该工作,因为编译器应该混淆。但是当我尝试它时,它有效。

所以。。有没有人知道更多关于这个的背景信息?


答案 1

为了确定应该调用哪个方法,编译器将遍历以下列表,如 JLS #5.3JLS #15.12.2 中所述:

  • 身份转换 (§5.1.1) = >方法 1(int a, int b)
  • 加宽基元转换 (§5.1.2)
  • 加宽参考转换 (§5.1.5)
  • 装箱转换 (§5.1.7), 后可选择扩大参考转换 ==> 方法 1(整数...a)
  • 取消装箱转换 (§5.1.8),然后选择性地进行加宽基元转换。

在您的情况下,第一点适用并被调用。method1(int, int)

(更准确地说,您的方法使用 varags,并且优先级低于简单的装箱转换。换句话说,如果有一个方法1(整数a,整数b),它将出现在方法1(整数...a) 在层次结构中)

为什么会这样?15.12.2 中的注释给出了一个提示:

这保证了在 Java SE 5.0 之前的 Java 编程语言中有效的任何调用都不会因为引入变量 arity 方法、隐式装箱和/或取消装箱而被视为模棱两可。


答案 2

第二种方法获胜。根据 Java 语言规范 (pdf)

第一阶段 (§15.12.2.2) 执行重载解析,不允许装箱或取消装箱转换,也不允许使用可变 arity 方法调用。

如果在此阶段找到适用的方法,则该方法获胜;不执行进一步的搜索。在你的情况下,它恰好是第二种方法,因为第一种方法是一种变量方法,也需要装箱。