不明确的可变参数方法

Ambiguous varargs methods

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

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");
    }
}

有人能告诉我这些方法不明确的原因吗?提前谢谢你。

int 和 Integer 之间的区别在于 Integer 是一个对象 type.you 可以用于查找类型 int 的最大数量或与整数进行比较的情况

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

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

在以下位置查找更多信息:http://docs.oracle.com/javase/7/docs/api/

因为他们模棱两可。根据 JLS,您可以进行加宽、装箱或装箱然后加宽。在您的示例中,有 2 个方法参数可以相互 boxed/unboxed。在编译时虽然它不可见 因为可变参数 ,它在 java 中总是不完全清楚。

即使 Sun 建议开发人员不要重载可变参数方法,编译器中也存在与之相关的错误 (see here)。

考虑方法签名

public static void foo(int a)

public static void foo(Integer a)

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

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

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

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

  1. The first phase (§15.12.2.2) performs overload resolution without permitting boxing or unboxing conversion, or the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the second phase.

  2. The second phase (§15.12.2.3) performs overload resolution while allowing boxing and unboxing, but still precludes the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the third phase.

  3. The third phase (§15.12.2.4) allows overloading to be combined with variable arity methods, boxing, and unboxing.

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

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

JLS 15.12.2.5. Choosing the Most Specific Method 说:

If more than one member method is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specific method is chosen.

...

One applicable method m1 is more specific than another applicable method m2, for an invocation with argument expressions e1, ..., ek, if any of the following are true:

...

m2 is not generic, m1 and m2 are applicable by variable arity invocation, and where the first k variable arity parameter types of m1 are S1, ..., Sk and the first k variable arity parameter types of m2 are T1, ..., Tk, the type Si is more specific than Ti for argument ei for all i (1 ≤ i ≤ k). Additionally, if m2 has k+1 parameters, then the k+1'th variable arity parameter type of m1 is a subtype of the k+1'th variable arity parameter type of m2.

在您的情况下,您有两个非泛型方法,它们可通过变量元数调用应用(即都有可变参数)。为了在您调用 method(1) 时选择其中一种方法,其中一种方法必须比另一种方法更具体。在您的情况下,每个方法只有一个参数,要使其中一个参数比另一个更具体,一个参数的类型必须是另一个方法参数的子类型。

因为 int 不是 Integer 的子类型并且 Integer 不是 int 的子类型,所以你的方法都不比另一个。因此 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).

时将选择第二种方法