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
),我们可以说int
s“小于”或“小于”double
s,按照这种逻辑,int
s 可以“提升”为double
s,double
s 可以是“降级”到int
s。
简单地说,一个可以扩展为另一个基元(例如int
-> float
-> double
)的基元比另一个基元更具体。例如,int
比double
更具体,因为1
可以提升为1.0
。
当您没有向这些重载的同名 vararg 方法传递任何参数时,由于返回实际上是相同的(分别为 0 和 0.0),编译器会选择使用接受 @987654340 类型的 vararg 的方法@ 因为它更具体。
那么,当您引入这些相同的方法时,它们分别采用int
s 和boolean
s(不能相互扩展的类型),编译器现在无法选择要使用的方法,因为int
s 不能像 int
s、float
s 和 double
s 那样“升级”或“降级”。因此,它会抛出一个编译错误。
我希望这可以帮助您了解正在发生的事情。
【讨论】:
您似乎混淆了double
和float
。 JLS 8 的第 5.1.2 节将 float
称为 double
19 种“扩展原语转换”之一。您的回答暗示double
可以扩大到float
。以上是关于Varargs Java 模糊调用的主要内容,如果未能解决你的问题,请参考以下文章