java - 确切的重载解决程序 - 为什么 f(1) 调用 f(int...arg) 和 f(long...arg) 没有歧义?

标签 java variadic-functions method-invocation ambiguous-call

我觉得这些是适用的:

JLS 15.12.2.4. Phase 3: Identify Methods Applicable by Variable Arity Invocation

JLS 15.12.2.5. Choosing the Most Specific Method

但是JLS语言太复杂了,我无法理解这一点。

void f(Integer... arg) { System.out.println("Integer..."); }

void f(int... arg) { System.out.println("int..."); }

void test() {
    f((short)1); // int... called 
    f(1); // c.ERR

我似乎理解那个(除此之外已经回答了 here ),尽管答案没有描述整个重载解决方案的所有细节(确切的顺序 - 尝试了哪些参数)过程 - 无论如何,我的问题主要在第二个代码片段中(int .. vs long ......)。但让我详细介绍一下上面的片段:

f((short)1) - 没有精确匹配,所以原始 short 首先被加宽(没有找到匹配),然后 short 被装箱成 Short(没有找到精确匹配), Short 被加宽(Number, Object) - 不匹配,现在进入第三阶段 (varargs) => 尝试以下内容:

  • 短...(不完全匹配 => 尝试原始加宽)
  • int...(找到完全匹配的 ,但不要停止,进一步搜索!)
  • long..., float..., double...(不匹配 => 尝试装箱)
  • 短...、数字...、对象...

因为没有找到其他匹配项 - 它编译正常。

f(1) - 没有完全匹配,所以原始 int 首先被加宽(没有找到匹配),然后 int 被装箱到 Integer(没有找到完全匹配),Integer 被加宽(Number, Object) - 不匹配,现在进入第三阶段 (varargs) => 尝试以下内容:

  • int...(找到了完全匹配的 ,但不要停止,进一步搜索!)
  • long..., float..., double...(不匹配 => 尝试装箱)
  • 整数...(现在不明确),数字...,对象...

由于找到了两个可能的匹配项 - 我们遇到了编译错误。

void f(long... arg) { System.out.println("long..."); }

void f(int... arg)  { System.out.println("int..."); }

void test() {
    f((byte)1); // int... called 
    f(1);       // int... called 
}

f(byte) - 第三阶段 (varargs) => 尝试了以下内容:

  • byte...(不匹配 => 尝试原始加宽)
  • short..., int...(找到匹配项,但要进一步观察),long...(应该是模棱两可的错误,但事实并非如此! ), float..., double...(现在还进行装箱并随后扩大引用范围,以寻找更多可能的匹配项来标记编译错误“不明确”)
  • 字节...、数字...、对象...

由于找到了两个可能的匹配项 - 应该是编译错误(但事实并非如此)。

我的猜测是有 4 个过程(精确原始匹配、原始扩展、装箱和精确引用匹配、引用扩展),如果在某个过程中找到匹配项,编译器将停止(该过程不会继续) , 但会尝试所有其他后续过程。在这种情况下,编译器在过程 2 处停止(仅 int... 匹配,但不匹配 long...),过程 3 和 4 没有产生匹配。

上面引用的answer在 SO 上提供以下标准:

for one parameter to be more specific than the other, the type of that parameter must be a subtype of the other method's parameter.

它可能适用于引用类型,但不适用于原始类型。

我好像明白了15.12.2.编译时步骤 2:确定方法签名。但就我而言,我们有“第三阶段 (§15.12.2.4) 允许将重载与可变元数方法、装箱和拆箱相结合。” - 但问题在于细节。

enter image description here enter image description here enter image description here

最佳答案

至于评论

for one parameter to be more specific than the other, the type of that parameter must be a subtype of the other method's parameter.

请注意,这适用于基本类型,请参阅 https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.10 规范中给出的关系暗示 int 是比 long 更具体的类型。

来自 https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12.2.5

A type S is more specific than a type T for any expression if S <: T (§4.10).

关于java - 确切的重载解决程序 - 为什么 f(1) 调用 f(int...arg) 和 f(long...arg) 没有歧义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57536610/

相关文章:

java - 泛型和可变参数 java

java - Java SE 7 中不可具体化类型的可变参数——怎么样?

python - 为什么在 Python 中不允许使用 foo(*arg, x)?

java - Java 中字符串操作的正确名称

java - 如何将一个字符串变成一个字符串数组?

java - jboss中类文件的热部署

java - 使用另一个列表对列表进行排序

Java 性能问题

java - 统计方法变量实例的方法调用次数

java - 我可以检查是否返回了 void 方法吗?