使用变量参数重载的方法(varargs)

时间:2015-08-30 05:27:33

标签: java overloading variadic-functions

看到此代码的输出后,我感到很惊讶:

public class File
{
    public static void main(String[] args)
    {
        movie();
    }

    static void movie(double... x)
    {
        System.out.println("No varargs");
    }

    static void movie(int... x)
    {
        System.out.println("One argument");
    }
}

输出,

One argument

为什么会这样?

我认为此代码无法编译,因为对movie()的调用是 不明确 ,但运行正常并输出One argument。< / p>

如果我将代码修改为:

public class File
{
    public static void main(String[] args)
    {
        movie();
    }

    static void movie(boolean... x)  //Changed the parameter type to boolean from double
    {
        System.out.println("No varargs");
    }

    static void movie(int... x)
    {
        System.out.println("One argument");
    }
}

有错误消息。

为什么第一个代码运行正常,但第二个代码出错?

4 个答案:

答案 0 :(得分:10)

此行为是由于intdouble更具体,而intboolean之间没有此类比较。

如JLS section 15.12.2.5中所述(强调我的):

  

对于带有参数表达式e1,...,ek的调用,如果满足以下任何条件,则一个适用的方法m1比另一个适用的方法m2 更具体

     
      
  • ...
  •   
  • m2不是通用的, m1和m2适用于变量arity调用,并且m1的前k个变量arity参数类型是S1,...,Sk和第一个k变量m2的arity参数类型为T1,...,Tk,对于所有i(1≤i≤k),对于参数ei,Si的类型比Ti 更具体。另外,如果m2具有k + 1个参数,则m1的第k + 1个变量参数类型是第k + 1个可变参数类型m2的子类型。
  •   

更具体的实际意味着后来定义为subtyping

  

如果S&lt;:T

,则对于任何表达式,类型S比类型T更具特异性

这意味着ST更具体,ST的子类型。对于原始类型,这归结为following properties

  
      
  • double&gt;浮
  •   
  • float&gt;长
  •   
  • 长&gt; INT
  •   
  • int&gt;炭
  •   
  • int&gt;短
  •   
  • 简短&gt;字节
  •   

请注意,boolean不存在。

因此,

public static void main(String[] args) {
    movie();
}

static void movie(int... x) { }
static void movie(short... x) { }
static void movie(double... x) { }
static void movie(byte... x) { }

编译和movie(byte... x)将被调用,因为它是最具体的。

然而,

public static void main(String[] args) {
    movie();
}

static void movie(int... x) { }
static void movie(boolean... x) { }

无法编译,因为boolean无法与int进行比较。

答案 1 :(得分:7)

  

非正式的直觉是一种方法是more specific而不是   另一个 if 可以传递第一种方法处理的任何调用   没有编译时错误的另一个

movie(int...x)视为 M1 ,将movie(double...x)视为 M2

方法M1 比M2更具体,因为我们可以使用给定方法M1的相同输入调用方法M2,而不会出现任何编译时错误。

因此,第一种方法M1的调用由M2定义处理。因为double可以毫无问题地处理int

但是我们不能使用给定方法M2的相同输入来调用M1,这很容易理解。

让我们检查以下示例,

public class Test {

    public static void main(String[] args) {
        movie();
    }

    static void movie(int... x) {
        System.out.println("One argument");
    }

    static void movie(short... x) {
        System.out.println("Short argument");
    }
}

<强>输出

Short argument

因为此处short比方法调用int的{​​{1}}更具体。

另一方面,movie()方法调用boolean引起混淆,因为编译器无法决定调用哪个方法,因为在这种情况下没有更具体的方法< / em>的

答案 2 :(得分:0)

我认为原因是java中的自动类型提升。默认情况下,如果表达式不包含浮点,则表达式的类型将提升为Integer类型或Long类型(取决于范围)。

因此,在第一种情况下,由于表达式中没有浮点值,因此当Integer赢得比赛时,void表达式将简单地解析为int varargs。

然而,在第二种情况下,编译器无法决定调用什么,即从重载方法中无法决定使用no-args调用哪一个。

答案 3 :(得分:0)

<强>答案:

1。如果我们使用像int这样的数据类型的对象作为Integer,它也会给出相同的错误。所以原因是它不能与Object类型一起使用,如果没有为函数指定参数,则会出错。

2。因为vararg将参数作为给定类型的数组。所以这就是为什么如果你不传递任何参数它将它作为一个零参数的数组并执行整数函数,因为它有一个带有整数参数的函数。

3。当你为两个不同的函数放置float和double而没有传递任何参数时,它会执行float参数函数。

  

解决方案:

     
      
  1. 不要使用String,Integer,Float,Double,Boolean和Char等对象类型。如果需要,请使用int,float,double和boolean   执行其中一个没有参数传递的函数。
  2.   
  3. 因此,在给定的示例中,我们需要为非原始数据类型为true或false的布尔对象指定一个布尔参数。
  4.   
public class File
{
    public static void main(String[] args)
    {
        movie(true);
    }

    static void movie(Boolean...x)  //Changed the parameter type to boolean from double
    {
        System.out.println("No varargs"+x);
    }

    static void movie(int...x)
    {
         System.out.println("One argument");
    }
}