模糊的varargs方法

这是一个不编译的代码示例:

public class Test { public static void main(String[] args) { method(1); } public static void method(int... x) { System.out.println("varargs"); } public static void method(Integer... x) { System.out.println("single"); } } 

有人能告诉我为什么这些方法不明确吗? 先谢谢你。

考虑方法签名

 public static void foo(int a) 

 public static void foo(Integer a) 

在装箱和拆箱之前,调用foo(1)不会有歧义。 为确保与早期版本的Java兼容,调用仍然是明确的。 因此,重载决策的第一阶段不允许装箱,取消装箱或变量arity调用,这些都是同时引入的。 变量arity调用是指通过为最后一个参数(而不是数组)传递一系列参数来调用varargs方法。

但是,方法签名的method(1)的解析允许装箱和拆箱,因为两种方法都需要变量arity调用。 由于允许拳击,两个签名都适用。 通常,当两个过载应用时,选择最具体的过载。 但是,您的签名都不比其他签名更具体(因为intInteger都不是另一个的子类型)。 因此,调用method(1)是不明确的。

您可以通过传递new int[]{1}来进行编译。

重载决策中使用了3个阶段( JLS 15.2.2 ):

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

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

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

在您的示例中,两个方法都是可变的arity方法,因此第三个阶段适用。

现在,由于我们有两种方法可供选择,我们寻找更具体的方法。

JLS 15.12.2.5。 选择最具体的方法说:

如果多个成员方法都可访问并适用于方法调用,则必须选择一个为运行时方法调度提供描述符。 Java编程语言使用选择最具体方法的规则。

一个适用的方法m1比另一个适用的方法m2更具体,用于参数表达式e1,…,ek的调用,如果满足以下任何条件:

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的子类型。

在您的情况下,您有两个非generics方法,适用于变量arity调用(即两者都有varargs)。 为了在调用method(1)时选择其中一个方法,其中一个方法必须比另一个方法更具体。 在您的情况下,每个方法只有一个参数,并且其中一个方法比另一个更具体,那个参数的类型必须是另一个方法参数的子类型。

由于int不是Integer的子类型,而Integer不是int的子类型,因此您的方法都不比其他方法更具体。 因此, The method method(int[]) is ambiguous for the type Test错误The method method(int[]) is ambiguous for the type Test

一个可行的例子:

 public static void method(Object... x) { System.out.println("varargs"); } public static void method(Integer... x) { System.out.println("single"); } 

由于IntegerObject的子类型,因此在调用method(1)时将选择第二种方法。

因为它们含糊不清。 根据JLS,你可以做扩大,拳击或拳击 – 然后扩大。 在您的示例中,有两个方法参数可以相互装箱/取消装箱。 在编译时虽然因为varargs而不可见,但在java中总是不是很清楚。

即使Sun建议开发人员不要重载varargs方法,编译器中也存在与之相关的错误( 参见此处 )。

int和Integer之间的区别在于Integer是一个对象类型。您可以在查找int类型的最大数量或与整数比较的情况下使用

整数对象已经与比较方法相关联:

 public static void method(int x, int y) { System.out.println(Integer.compare(x, y)); } 

有关更多信息,请访问: http : //docs.oracle.com/javase/7/docs/api/