Varargs Java 模糊调用

Posted

技术标签:

【中文标题】Varargs Java 模糊调用【英文标题】:Varargs Java Ambiguous Call 【发布时间】:2015-10-16 02:41:51 【问题描述】:

我对 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;

【问题讨论】:

有趣的问题。 您可能会找到问题的答案here。 【参考方案1】:

这里适用的一般规则是:如果一个方法签名严格比另一个更具体,那么 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. Choosing the Most Specific Method

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

...

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

...

m2 不是泛型的,m1 和 m2 可以通过严格或松散的调用来应用,其中 m1 有形参类型 S1,...,Sn 和 m2 有形参类型 T1,...,Tn,类型对于所有 i (1 ≤ i ≤ n, n = k),对于自变量 ei,Si 比 Ti 更具体

...

如果 S <: t s>


4.10。子类型

4.10.1. Subtyping among Primitive Types

双 >1 浮点数

浮点数 >1 长

long >1 int

【讨论】:

【参考方案2】:

正如this answer 中提到的,在选择要使用的重载方法时有一些规则。

引用:

    原始扩展使用可能的最小方法参数 包装器类型不能扩展到另一个包装器类型 您可以从 int 到 Integer 并扩大到 Object 但不能到 Long 加宽胜过拳击,拳击胜过 Var-args。 你可以先装箱然后加宽(一个 int 可以通过 Integer 变成 Object) 你不能先加宽再开箱(一个 int 不能变长) 您不能将 var-args 与 both 加宽 装箱结合使用。

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

因此,牢记这些规则,我们可以了解这里发生了什么:

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

简单地说,一个可以扩展为另一个基元(例如int -> float -> double)的基元比另一个基元更具体。例如,intdouble更具体,因为1 可以提升为1.0

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

那么,当您引入这些相同的方法时,它们分别采用ints 和booleans(不能相互扩展的类型),编译器现在无法选择要使用的方法,因为int s 不能像 ints、floats 和 doubles 那样“升级”或“降级”。因此,它会抛出一个编译错误。

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

【讨论】:

您似乎混淆了doublefloat。 JLS 8 的第 5.1.2 节将 float 称为 double 19 种“扩展原语转换”之一。您的回答暗示double 可以扩大到float

以上是关于Varargs Java 模糊调用的主要内容,如果未能解决你的问题,请参考以下文章

反射 varargs 调用警告

如何通过 dbus 调用 varargs 函数?

Java 变长參数Varargs

java可变参数Varargs

Java Varargs 可变参数使用

Oracle 等效于 Java 的 Varargs