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

Method overloading with variable arguments (varargs)

看到这段代码的输出我很惊讶:

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.

如果我修改代码为:

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");
    }
}

有一条错误消息。

为什么第一个代码 运行 没问题,但第二个却出错?

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

所以在第一种情况下,void 表达式被简单地解析为 int varargs,因为 Integer 由于表达式中没有浮点值而赢得了比赛。

然而,在第二种情况下,编译器无法决定调用什么,即在重载方法中它无法决定调用无参数的方法。

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

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

One applicable method m1 is more specific than another applicable method m2, for an invocation with argument expressions e1, ..., ek, if any of the following are true:

  • ...
  • m2 is not generic, and m1 and m2 are applicable by variable arity invocation, and where the first k variable arity parameter types of m1 are S1, ..., Sk and the first k variable arity parameter types of m2 are T1, ..., Tk, the type Si is more specific than Ti for argument ei for all i (1 ≤ i ≤ k). Additionally, if m2 has k+1 parameters, then the k+1'th variable arity parameter type of m1 is a subtype of the k+1'th variable arity parameter type of m2.

更具体的实际含义稍后定义为subtyping:

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

这意味着 ST 更具体,因为 ST 的子类型。对于基本类型,这归结为 following properties:

  • double > float
  • float > long
  • long > int
  • int > char
  • int > short
  • short > byte

请注意 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 进行比较。

The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time error.

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

因为这里 shortint 更具体的方法调用 movie().


另一方面,对于 boolean 方法调用 movie(); 会引起混淆,因为编译器无法决定调用哪个方法,因为在这种情况下没有 这样的点更具体的方法.

答案:

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

2。由于 vararg 将参数作为给定类型的数组。所以这就是为什么如果您不传递任何参数,它会将其视为具有零参数的数组并执行整数函数,因为它获得了具有整数参数的函数之一。

3。当您为两个不同的函数放置 float 和 double 并且不传递任何参数时,它会执行 float 参数函数。

Solution:

  1. Do not use object types like String, Integer, Float, Double, Boolean, and Char. Instead use int, float, double, and boolean if want to execute one of the functions with no arguments passing.
  2. So in the given example we need to specifiy a boolean argument for the Boolean object of non-primitive data type true or false.
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");
    }
}