使用varargs重载功能

时间:2013-12-19 22:29:33

标签: java overloading variadic-functions

这不会编译:

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是原始的,因此在两种情况下都应该调用第二种方法。这是正常的行为吗?

我找到了: Bug report Stack overflow

3 个答案:

答案 0 :(得分:4)

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

首先,varargs语法实际上只是用于传递数组的语法糖。所以method(7)实际上会传递一些......某种东西。

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

如果有两个或更多可能有效的重载(即正确的方法名称,正确的参数数量,可转换值),则解析过程将选择与需要转换的匹配完全匹配的重载,并且如果唯一的候选人需要转换。 (这是对规则的极大简化......请参阅JLS section 15.12了解完整的故事......并为长期/困难的阅读做好准备!)

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

如果您将varargs调用更改为通过显式Integer[]int[]的调用,您现在可以完全匹配两个重载中的一个...并且上面的规则说这是没有暧昧。


  

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

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

答案 1 :(得分:2)

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

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

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

答案 2 :(得分:0)

答案很难。但它在JLS §15.12. Method Invocation Expressions中有所描述。在这些规范中,“ variable arity ”方法是具有可变数量参数的方法,因此varargs。

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

  

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

     
      
  • 对于1≤i<1。 n,e i 的类型,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 <:   乙<子>升 [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 ,   屋[]。

    •   
    • 如果第二种方法是通用的,则让R 1 ... R p (p≥1)为其类型   参数,让B l 是R l (1≤l≤p)的声明边界,让A 1 ...    p 是此调用的推断类型参数(第15.12.2.7节)   在初始约束条件下,T i &lt;&lt; U i (1≤i≤k-1)且T i &lt;&lt;&lt;&lt;&lt;&lt; U k (k≤   i≤n),让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

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

    •   
  2.   

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

您的方法与这些条件不匹配,因此没有“ Most Specific ”方法。所以,它说得更进一步:

  

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

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

         
        
    • 如果未声明其中一个最大特定方法   摘要,这是最具体的方法。

    •   
    • 否则,如果声明了所有最大特定方法   摘要,以及所有最大特定方法的签名   具有相同的擦除(§4.6),然后选择最具体的方法   任意地在最大特定方法的子集中   具有最具体的回报类型。

           

      但是,最具体的方法是考虑抛出一个检查   当且仅当声明该异常或其擦除时的异常   每种最具体方法的抛出条款。

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

  •   

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