[英]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 整数
正如在这个答案中提到的,在选择要使用的重载方法时遵循一些规则。
报价:
- 原始扩展使用尽可能小的方法参数
- Wrapper 类型不能扩展到另一个 Wrapper 类型
- 你可以从 int 装箱到 Integer 并加宽到 Object 但不能加宽到 Long
- 加宽击败拳击,拳击击败 Var-args。
- 你可以装箱然后加宽(一个整数可以通过整数变成对象)
- 你不能先加宽然后框(一个整数不能变成长)
- 不能合并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
)的原语比另一个更具体。 例如, int
比double
更具体,因为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.