使用原始类型和包装类的varargs重载时为什么会出现模糊错误?

我不明白为什么在这里的情况1,它没有给出编译错误,相反在情况2(varargs),它给出了编译错误。 任何人都可以详细说明编译器在这两种情况下的差异吗? 我经历了很多关于它的post,但还不能理解它。

情况1

public class Test { public void display(int a) { System.out.println("1"); } public void display(Integer a) { System.out.println("2"); } public static void main(String[] args) { new Test().display(0); } } 

输出为: 1

案例#2

 public class Test { public void display(int... a) { System.out.println("1"); } public void display(Integer... a) { System.out.println("2"); } public static void main(String[] args) { new Test().display(0); } } 

编译错误

 The method display(int[]) is ambiguous for the type Test 

在第一个示例中, display(int)方法在严格调用上下文中调用,而display(Integer)在松散调用上下文中调用(因为需要自动装箱)。 因此编译器根据JLS选择display(int)方法。 调用上下文在JLS 5.3中进行了解释。 调用上下文

在第二个示例中,两个方法都在松散的调用上下文中调用,因此编译器需要找到最具体的方法JLS 15.12.2.5选择最具体的方法 。 由于int不是Integer的子类型,因此没有最具体的方法,编译器会抛出编译错误。

你可以在这里找到我对类似编译错误的解释。 使用Java 8三元条件和非盒装原语的方法重载歧义

适用于此案例的部分:

确定适用的方法分为3个阶段。

第一阶段(§15.12.2.2)执行重载解析而不允许装箱或拆箱转换,或使用变量arity方法调用 。 如果在此阶段没有找到适用的方法,则处理继续到第二阶段。

第二阶段(第15.12.2.3节)执行重载解析,同时允许装箱和拆箱, 但仍然排除使用变量arity方法调用 。 如果在此阶段没有找到适用的方法,则处理继续到第三阶段。

第三阶段(§15.12.2.4)允许重载与变量arity方法 ,装箱和拆箱相结合。

对于第一个示例,只有display(int)方法在第一个阶段匹配,因此选择它。 对于第二个示例,两个方法在第三阶段匹配,因此选择最具体方法算法发挥作用JLS 15.12.2.5选择最具体的方法 :

m2不是通用的,m1和m2适用于变量arity调用,并且m1的前k个变量arity参数类型是S1,…,Sk和m2的前k个变量arity参数类型是T1,..对于所有i(1≤i≤k),对于参数ei,Si的类型比Ti更具体。 另外,如果m2具有k + 1个参数,则m1的第k + 1个可变参数类型是第m + 1个可变参数类型m2的子类型。

如前所述,由于int <:Integer不满足,因此没有最具体的方法。

在Java Version 1.5之后,引入了一个名为autoboxing的很酷的function,它使编译器能够将原始类型转换为Wrapper Type 。 因此,在编译期间,两种方法都是相同的。

  public void display(int... a) { System.out.println("1"); } public void display(Integer... a) { System.out.println("2"); } 

由于在编译期间执行autoboxing因此该function将被视为相同的方法。 因此,在Java中重载方法时要小心自动装箱

更多你在这里找到..

方法重载的最佳实践