繁体   English   中英

可变参数 Java 歧义调用

[英]Varargs Java Ambiguous Call

我对 Java 的varargs方法有点困惑:

public static int sum(int ...a) {
    return 0;
}

public static double sum(double ...a) {
    return 0.0;
}

当我尝试在不传递任何参数的情况下调用sum() ,会调用int版本的方法。 我不明白为什么; 通常编译器必须引发错误。

相比之下,当我尝试不带任何参数调用sum时,以下代码会生成编译器错误:

public static int sum(int ...a) {
    return 0;
}

public static boolean sum(boolean ...a) {
    return true;
}

这里适用的一般规则是:如果一个方法签名比另一个更具体,那么 Java 会毫无错误地选择它。

直观地说,如果您可以完全删除它,则方法签名会更具体,而另一个不太具体的方法签名将适用于每个现有调用。

当在签名sum(int... args)sum(double... args) ,签名sum(int... args)更具体,因为该方法的任何调用也可以传递通过应用扩大转换来sum(double... args) 对于sum(boolean... args)方法,同样的情况不成立,它不能被类似地转换。

Java 语言规范,SE 8 版本:

15.12. 方法调用表达式

15.12.2.5. 选择最具体的方法

Java 编程语言使用选择最具体的方法的规则。

...

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

...

  • m2 不是泛型,m1 和 m2 可通过严格或松散调用适用,并且其中 m1 具有形式参数类型 S1, ..., Sn 和 m2 具有形式参数类型 T1, ..., Tn,类型 Si更多对于所有 i (1 ≤ i ≤ n, n = k) 的参数 ei 比 Ti特定

...

对于任何表达式,如果 S <: T (§4.10),则类型 S 比类型 T 更具体。


4.10. 子类型

4.10.1. 原始类型之间的子类型化

双 >1 浮点数

浮动 >1 长

长 >1 整数

正如在这个答案中提到的,在选择要使用的重载方法时遵循一些规则。

报价:

  1. 原始扩展使用尽可能小的方法参数
  2. Wrapper 类型不能扩展到另一个 Wrapper 类型
  3. 你可以从 int 装箱到 Integer 并加宽到 Object 但不能加宽到 Long
  4. 加宽击败拳击,拳击击败 Var-args。
  5. 你可以装箱然后加宽(一个整数可以通过整数变成对象)
  6. 你不能先加宽然后框(一个整数不能变成长)
  7. 不能合并VAR-ARGS,拓宽拳击。

(让我们像这样重新定义规则 1:“原始扩展尽可能使用最具体的方法参数。”)

因此,考虑到这些规则,我们可以了解这里发生了什么:

根据第一条规则,原始扩展尽可能使用最具体的方法参数。 由于int由非十进制数(例如1 )表示,而double由精度比float (例如1.0 )高 32 个字节的十进制数表示,我们可以说int s“小于" 或“小于” double s,根据该逻辑, int s 可以“提升”为double s,而double s 可以“降级”为int s。

简而言之,一个可以扩展为另一个原语(例如int -> float -> double )的原语比另一个更具体 例如, intdouble更具体,因为1可以提升为1.0

当您不向这些重载的同名 vararg 方法传递任何参数时,由于返回实际上相同(分别为 0 和 0.0),编译器将选择使用接受int类型的 vararg 的方法,因为它更多具体的

因此,当您引入这些分别接受int s 和boolean s(不能相互扩展的类型)的相同方法时,编译器现在无法选择要使用的方法,因为int s 不能“提升”或“降级” " 像int s、 float s 和double s。 因此,它会抛出编译错误。

我希望这可以帮助您了解正在发生的事情。

暂无
暂无

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

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