有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

带变量参数的java方法重载

我认为这是一个有点愚蠢的问题,但我不知道为什么

代码

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

我期望的结果

4.0
this is variant args//30
this is variant args//60

控制台中的实际结果:

4.0
30.0
this is variant args//60

我不知道为什么sum(10, 20)30.0的结果,而不是变量参数的30


共 (6) 个答案

  1. # 1 楼答案

    答案在JLS section 15.12.2中。基本上,编译器试图找到任何适用的方法,而不必展开varargs,只有在必须的情况下才使用varargs:

    The remainder of the process is split into three phases, to ensure compatibility with versions of the Java programming language prior to Java SE 5.0. The phases are:

    • The first phase (§15.12.2.2) performs overload resolution without permitting boxing or unboxing conversion, or the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the second phase. [...]

    • The second phase (§15.12.2.3) performs overload resolution while allowing boxing and unboxing, but still precludes the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the third phase. [...]

    • The third phase (§15.12.2.4) allows overloading to be combined with variable arity methods, boxing, and unboxing.

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

  2. # 2 楼答案

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

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

    IDE会在这里警告您关于intdouble的隐式转换


    编辑:正如@OlegEterkhin在评论中提到的,请参见JLS, section 15.2.2,了解编译器选择将使用哪个方法的过程

    不,这行不通:

    int x = sum(10, 20);
    
  3. # 3 楼答案

    这种行为在specification中定义。“变量算术方法、装箱和拆箱”在方法签名解析的第三阶段处理,首先尝试在不使用变量算术方法的情况下匹配签名

  4. # 4 楼答案

    类型推断比varargs具有某种优先级。由于您使用两个参数调用一个方法,因此在搜索varargs方法(即使使用正确的类型)之前,它会尝试使用两个参数查找匹配项(即使使用类型推断)

  5. # 6 楼答案

    基于这篇文章Varargs in method overloading in Java

    选择要选择的重载方法、组合装箱、加宽和变量参数时,需要遵循一些规则:-

    Primitive widening uses the smallest method argument possible
    Wrapper type cannot be widened to another Wrapper type
    You can Box from int to Integer and widen to Object but no to Long
    Widening beats Boxing, Boxing beats Var-args.
    You can Box and then Widen (An int can become Object via Integer)
    You cannot Widen and then Box (An int cannot become Long)
    You cannot combine var-args, with either widening or boxing