【问题标题】:Method overloading with variable argument带变量参数的方法重载
【发布时间】:2014-04-08 16:00:12
【问题描述】:

我认为这会是一个有点愚蠢的问题,但我不确定为什么会这样。

代码;

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。

【问题讨论】:

标签: java variadic-functions


【解决方案1】:

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

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

IDE 会在此处警告您有关 intdouble 的隐式转换。


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

不,这行不通:

int x = sum(10, 20);

【讨论】:

  • 在这里做出选择的并不是 JVM,而是编译器。
  • JLS 15.12.2 是规范的相关部分,它甚至非常易读。
【解决方案2】:

答案在JLS section 15.12.2。基本上,编译器试图找到任何适用的方法不必扩展可变参数,只有在必须时才使用可变参数:

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

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

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

  • 第三阶段(第 15.12.2.4 节)允许将重载与可变参数方法、装箱和拆箱相结合。

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

【讨论】:

    【解决方案3】:

    行内:

    System.out.println(sum(10, 20));
    

    参数的个数sum(double a, double b)的签名相匹配,这是最准确的方法,也是编译器选择的方法.

    详情请参阅15.12.2. Compile-Time Step 2: Determine Method Signature

    【讨论】:

      【解决方案4】:

      基于这篇帖子Varargs in method overloading in Java

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

      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
      

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

          此行为在specification 中定义。 “可变参数方法、装箱和拆箱”在方法签名解析的第三阶段处理,在第一次尝试匹配签名而不使用可变参数方法之后。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-09-13
            相关资源
            最近更新 更多