繁体   English   中英

不明确的可变参数方法

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

有人能告诉我这些方法含糊不清的原因吗? 先感谢您。

重载解决方案 ( JLS 15.2.2 ) 使用了 3 个阶段:

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

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

  3. 第三阶段(第 15.12.2.4 节)允许将重载与可变数量方法、装箱和拆箱相结合。

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

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

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

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

...

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

...

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

在您的情况下,您有两个非通用方法,它们适用于变量 arity 调用(即都有可变参数)。 为了在调用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)时将选择第二种方法。

考虑方法签名

public static void foo(int a)

public static void foo(Integer a)

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

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

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

因为它们模棱两可的。 根据 JLS,您可以进行加宽、拳击或拳击然后加宽。 在您的示例中,有 2 个方法参数可以相互装箱/拆箱。 在编译时,虽然由于 varargs不可见,但在 java 中始终不是绝对清楚。

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

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

Integer 对象已经与像 compare 方法这样的方法相关联:

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM