Java 不明确的varargs方法

Java 不明确的varargs方法,java,methods,variadic-functions,Java,Methods,Variadic Functions,下面是一个未编译的代码示例: 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) { Sy

下面是一个未编译的代码示例:

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是一种对象类型。您可以在查找int类型的最大数目或与Integer进行比较等情况下使用

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

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

查看更多信息:

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

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

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

更多信息请访问:

,因为它们模棱两可。根据JLS,您可以进行加宽、装箱或装箱然后加宽。在您的示例中,有两个方法参数可以相互装箱/取消装箱。在编译时,由于varargs的缘故,是不可见的,而在java中,varargs总是不是绝对清晰的


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

因为它们不明确。根据JLS,您可以进行加宽、装箱或装箱然后加宽。在您的示例中,有两个方法参数可以相互装箱/取消装箱。在编译时,由于varargs的缘故,是不可见的,而在java中,varargs总是不是绝对清晰的


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

考虑方法签名

public static void foo(int a)

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

但是,方法签名的
方法(1)
解析允许装箱和取消装箱,因为这两种方法都需要变量arity调用。由于允许装箱,所以两个签名都适用。通常,当应用两个重载时,会选择最具体的重载。但是,两个签名都不比另一个更具体(因为
int
Integer
都不是另一个的子类型)。因此,调用
方法(1)
是不明确的


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

考虑方法签名

public static void foo(int a)

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

但是,方法签名的
方法(1)
解析允许装箱和取消装箱,因为这两种方法都需要变量arity调用。由于允许装箱,所以两个签名都适用。通常,当应用两个重载时,会选择最具体的重载。但是,两个签名都不比另一个更具体(因为
int
Integer
都不是另一个的子类型)。因此,调用
方法(1)
是不明确的


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

重载解析()中使用了三个阶段:

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

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

  • 第三阶段(§15.12.2.4)允许重载与可变算术方法、装箱和拆箱相结合

  • 在您的示例中,这两种方法都是可变算术方法,因此第三阶段适用

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

    说:

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

    对于参数表达式e1、…、ek的调用,如果以下任一项为真,则一个适用方法m1比另一个适用方法m2更具体:

    m2不是泛型的,m1和m2通过变量算术调用适用,如果m1的前k个变量算术参数类型是S1,…,Sk,m2的前k个变量算术参数类型是T1,…,Tk,那么对于所有i(1),参数ei,类型Si比Ti更具体≤ 我≤ k) 。此外,如果m2具有k+1参数,则m1的k+1变量算术参数类型是m2的k+1变量算术参数类型的子类型

    在您的例子中,有两个非泛型方法可通过变量arity调用应用(即都有varargs)。为了在调用
    方法(1)
    时选择其中一种方法,t