使用变量参数重载的方法

rap*_*pot 4 java variadic-functions

我认为这会是一个愚蠢的问题,但我不知道为什么会这样.

码;

public class OverloadingTest {
    public static int sum(int ...a){
        int sum=0;
        for(int i : a){
            sum += i;
        }
        System.out.print("this is variant args//");
        return sum;
    }

    public static double sum(double a, double b) {
        return a + b;
    }

    public static void main(String[] args) {
        System.out.println(sum(1.5, 2.5));
        System.out.println(sum(10, 20));
        System.out.println(sum(10, 20,30));
    }
}
Run Code Online (Sandbox Code Playgroud)

结果我期待;

4.0
this is variant args//30
this is variant args//60
Run Code Online (Sandbox Code Playgroud)

控制台中的实际结果:

4.0
30.0
this is variant args//60
Run Code Online (Sandbox Code Playgroud)

我不能确定为什么sum(10, 20)30.0的结果,而不是变量参数的30.

fge*_*fge 6

这是因为编译器总是选择使用最具体的方法.

由于您的第二次调用有两个参数,并且int可以转换为double不失精度(参见JLS,第5.1.2节),编译器会选择调用您的双参数方法.

一个IDE将在这里提醒你有关隐intdouble转换.


编辑:正如@OlegEterkhin在注释中提到的,请参阅JLS,第15.2.2节,了解编译器用于选择将使用哪种方法的过程.

不,这不起作用:

int x = sum(10, 20);
Run Code Online (Sandbox Code Playgroud)

  • 这不是JVM在这里做出的选择 - 它是编译器. (4认同)
  • [JLS 15.12.2](http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2)是speci的相关部分,它甚至是很可读. (4认同)

Jon*_*eet 5

答案在JLS第15.12.2节中.基本上,编译器试图找到任何适用的方法,不必扩展varargs,只有使用varargs,如果它必须:

该过程的其余部分分为三个阶段,以确保与Java SE 5.0之前的Java编程语言版本兼容.阶段是:

  • 第一阶段(§15.12.2.2)执行重载解析而不允许装箱或拆箱转换,或使用变量arity方法调用.如果在此阶段没有找到适用的方法,则处理继续到第二阶段.[...]

  • 第二阶段(§15.12.2.3)执行重载解析,同时允许装箱和拆箱,但仍然排除使用变量arity方法调用.如果在此阶段没有找到适用的方法,则处理继续到第三阶段.[...]

  • 第三阶段(§15.12.2.4)允许重载与变量arity方法,装箱和拆箱相结合.

在这种情况下,第一阶段确实找到匹配,因为从隐式转换到,sum(double, double)所以适用于调用.sum(10, 20)intdouble