使用varargs重载function

这不会编译:

public class Methods { public static void method(Integer... i) { System.out.print("A"); } public static void method(int... i) { System.out.print("B"); } public static void main(String args[]) { method(7); } } 

这将编译和工作:

 public class Methods { public static void method(Integer i) { System.out.print("A"); } public static void method(int i) { System.out.print("B"); } public static void main(String args[]) { method(7); } } 

第一个和第二个例子非常相似。 首先使用varargs,其次不使用varargs。 为什么一个有效,第二个没有。 7是原始的,因此在两种情况下都应该调用第二种方法。 这是正常的行为吗?

我发现了: 错误报告 堆栈溢出

这是对正在发生的事情的高级非正式总结。

首先,varargs语法实际上只是用于传递数组的语法糖。 因此method(7)实际上将传递一个……的数组。

但是一阵什么? 这里有两个选项对应于方法的两个重载; 即int[]Integer[]

如果有两个或更多可能有效的重载(即正确的方法名称,正确的参数数量,可转换值),那么解析过程将选择与需要转换的匹配完全匹配的重载,并且如果只有候选者则会抱怨要求转换。 (这是对规则的大幅简化……有关完整的故事,请参阅JLS 第15.12节 ……并做好长时间/难以阅读的准备!)

所以你的第一个例子中发生的事情是,它试图在两种方法之间做出决定,这两种方法都需要转换; ie int to int[]int to Integer[] 。 基本上它无法决定使用哪种替代方案。 因此编译错误表明调用是模糊的。

如果你将varargs调用更改为通过显式Integer[]int[]的调用,那么现在可以获得与两个重载中的一个完全匹配…并且上面的规则说这不是模棱两可的。


我理解为:7是原始的,所以它应该转换为array – int[]

问题是7 可以通过首先自动装箱int转换为Integer[] ….

必须在数组中传递多个参数,但varargs隐藏进程。 在上面的varargs方法中,参数充当带引用名称的int数组。 因此,如果您将其更改为:

  public static void main(String args[]) { int[] s = {7}; method(s); } 

第一堂课将编译并正常工作。

答案很难。 但它在JLS§15.12中有所描述。 方法调用表达式 。 在这些规范中,“ 变量arity ”方法是具有可变数量的参数的方法,因此varargs。

§15.12.2.4。 阶段3:确定适用的变量Arity方法

当且仅当满足以下所有条件时,方法m是适用的变量方法:

  • 对于1≤ii ,a i的类型可以通过方法调用转换为S i来转换。

  • 如果k≥n,则对于n≤i≤k,可以通过方法调用转换将e i ,A i的类型转换为S n的分量类型。

  • 如果k!= n,或者如果k = n并且An不能通过方法调用转换转换为S n [],则可以在调用点访问S n的擦除类型(第4.6节)。

  • 如果m是如上所述的通用方法,那么U l <: B l [R 1 = U 1 ...,R p = U p ](1≤l≤p)。

如果未找到适用的变量arity方法,则会发生编译时错误。

否则, 在适用的变量方法中选择最具体的方法(第15.12.2.5节 )。

因此,我们应该进一步研究§15.12.2.5 。

§15.12.2.5。 选择最具体的方法

一个名为m变量arity成员方法比另一个具有相同名称的变量arity成员方法更具体:

  1. 一个成员方法有n个参数,另一个有k个参数,其中n≥k,和:

    • 第一成员方法的参数类型是T 1 ,...,T n-1 ,T n []。

    • 另一种方法的参数类型是U 1 ,...,U k-1 ,Uk []。

    • 如果第二种方法是通用的,则让R 1 ... R p (p≥1)为其类型参数,设B l为R l的声明界(1≤l≤p),设A 1 ... A p是在初始约束T i << U i (1≤i≤k-1)和T i << U k (k≤i≤n)下对此调用推断的类型参数(第15.12.2.7节),以及令S i = U i [R 1 = A 1 ,...,R p = A p ](1≤i≤k)。

    • 否则,令S i = U i (1≤i≤k)。

    • 对于从1到k-1的所有j,T j <: S j ,和,

    • 对于从k到n的所有j,T j <: S k ,和,

    • 如果第二种方法是如上所述的通用方法,那么
      A l <: B l [R 1 = A 1 ,...,R p = A p ](1≤l≤p)。

T <: S表示T是S的子类型

您的方法与这些条件不匹配,因此没有“ 最具体 ”方法。 所以,它说了一点:

可能没有方法是最具体的,因为有两种或更多种方法是最具体的。 在这种情况下:

  • 如果所有最大特定方法都具有覆盖等效(§8.4.2)签名,则:

    • 如果其中一个最大特定方法未被声明为abstract,则它是最具体的方法。

    • 否则,如果所有最大特定方法都被声明为抽象,并且所有最大特定方法的签名具有相同的擦除(第4.6节),那么在具有最大特定方法的子集中任意选择最具体的方法。最具体的退货类型。

      但是,当且仅当在每个最大特定方法的throws子句中声明了该exception或其擦除时,才会考虑使用最具体的方法抛出已检查的exception。

  • 否则,我们说方法调用是不明确的,并且发生编译时错误。

所以,结论是:你的方法在JLS之后是模糊的。