Varargs在Java中的方法重载

Tin*_*iny 21 java overloading variadic-functions java-6

以下代码无法编译.

package varargspkg;

public class Main {

    public static void test(int... i) {
        for (int t = 0; t < i.length; t++) {
            System.out.println(i[t]);
        }

        System.out.println("int");
    }

    public static void test(float... f) {
        for (int t = 0; t < f.length; t++) {
            System.out.println(f[t]);
        }

        System.out.println("float");
    }

    public static void main(String[] args) {
        test(1, 2);  //Compilation error here quoted as follows.
    }
}
Run Code Online (Sandbox Code Playgroud)

发出编译时错误.

对于测试的引用是不明确的,varargspkg.Main中的方法test(int ...)和varargspkg中的方法test(float ...)匹配

这似乎是显而易见的,因为在方法调用的参数值test(1, 2);可以提升int以及float

如果任何一个或两个参数后缀为Ff,则编译.


但是,如果我们使用相应的包装器类型表示方法签名中的接收参数,如下所示

public static void test(Integer... i) {
    System.out.println("Integer" + Arrays.asList(i));
}

public static void test(Float... f) {
    System.out.println("Float" + Arrays.asList(f));
}
Run Code Online (Sandbox Code Playgroud)

那么对方法的调用test(1, 2);不会发出任何编译错误.在这种情况下要调用的方法是接受一个Integervarargs参数的方法(前面代码片段中的第一个).

为什么在这种情况下错误与第一种情况没有报告?这里似乎都应用了自动装箱和自动类型提升.是否首先应用自动装箱以便解决错误?

Oracle文档说,

一般来说,你不应该重载varargs方法,否则程序员很难弄清楚调用哪些重载.

这个链接的最后一句话.然而,这是为了更好地理解varargs.

另外添加下面的代码编译就好了.

public class OverLoading {

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

    public static void load(int i) {
        System.out.println("int");
    }

    public static void load(float i) {
        System.out.println("float");
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:

以下是指示编译错误的快照.我创建了一个新的应用程序,因此包名称不同.

在此输入图像描述

我正在使用JDK 6.

Roh*_*ain 10

您可以WidenBox,但你不能两者都做,除非你是boxing and wideningObject(一个int,整数(拳击),然后整数到对象(扩大)是合法的,因为每个类的子类Object,所以有可能Integer被传递到Object参数)

类似地,intto Number也是合法的(int - > Integer - > Number)因为Number是超类,Integer所以它是可能的.

我们在你的例子中看到这个: -

public static void test(Integer...i)

public static void test(Float...f)
Run Code Online (Sandbox Code Playgroud)

选择要选择的重载方法,组合Boxing,Widening和Var-args时,遵循一些规则: -

  1. 原始扩展使用smallest可能的方法参数
  2. 包装类型不能扩展到另一种包装类型
  3. 您可以从int到Integer并将其扩展为Object但不包含Long
  4. 加宽节拍拳击,拳击节拍Var-args.
  5. 你可以盒子然后加宽(一个int可以成为Object通过Integer)
  6. 你不能加宽然后盒子(一个int不能成为Long)
  7. 你不能将var-args与拓宽或装箱结合起来

因此,根据上述规则: -

当您将两个整数传递给上述函数时,

  • 根据规则3,它必须首先Widened然后 Boxed适合a Long,根据规则5是非法的(你不能加宽然后盒子).
  • 因此,它被Boxed存储在Integervar-args中.

但在第一种情况下,你有var-args原始类型的方法: -

public static void test(int...i)
public static void test(float...f)
Run Code Online (Sandbox Code Playgroud)

然后test(1, 2)可以调用这两个方法(因为它们都不适合rule 1应用): -

  • 在第一种情况下它将是 var-args
  • 在第二种情况下,它将是加宽然后Var-args(允许)

现在,当你有一个只有一个int和一个flost的方法时: -

public static void test(int i)
public static void test(float f)
Run Code Online (Sandbox Code Playgroud)

然后在调用时test(1),遵循规则1,并且选择最小可能的加宽(即int,根本不需要加宽的地方).因此将调用第一个方法.

有关更多信息,请参阅 JLS - Method Invocation Conversion