方法调用与varargs运算符不明确

时间:2014-08-23 18:36:12

标签: java overloading variadic-functions scjp

下面的代码会产生语法错误:

  

方法f(int[])对于类型C

是不明确的

我的代码:

public class C{

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

    public static void f(Integer... i)
    {
        System.out.println("b");
    }

    public static void main(String[] args) {
        f(new Integer(2));
    }
}

如果我使用数组表示法[]而不是...并使用f(new Integer[]{3,4,5})正确调用函数,编译器可以正确地决定我要使用哪种方法。

编译器无法决定使用...调用哪个函数的原因是什么?

4 个答案:

答案 0 :(得分:2)

JLS, Secion 15.12, "Method Invocation Expressions"中解释了为特定调用站点查找“正确”方法的过程。经过基本完整性检查的简短序言后,相关部分从section 15.12.2.1, Identify Potentially Applicable Methods开始。在您的情况下,根据此定义,两种方法都可能适用

后续流程包括三个阶段。在您的情况下,该方法是变量arity 方法(由于“varargs”)。所以它立即从15.12.2.4, Phase 3: Identify Applicable Variable Arity Methods开始。

  

当且仅当满足以下所有条件时,方法m才是适用的变量方法:

     
      
  • 对于1≤i<1。 n,ei的类型Ai可以通过方法调用转换为Si来转换。
  •   
  • ...
  •   

(其他条件与此无关)

Method Invocation Conversion (JLS, 5.3)允许以下转换:

  • 身份转换(第5.1.1节)
  • 扩大原始转换(第5.1.2节)
  • 扩大参考转换(第5.1.5节)
  • 拳击转换(§5.1.7),可选地后跟加宽参考转换
  • 一个拆箱转换(第5.1.8节),可选地后跟一个加宽的基元转换。

IntegerInteger的转换是身份转换(第一个要点)。从Integerint的转换是一个拆箱转换(最后一个要点)。

因此,根据规范,这两种方法都是“适用的变量方法”。

答案 1 :(得分:0)

规则为WBV/WAV 加宽 - &gt; (自动)拳击 - &gt;在方法重载的情况下,Varargs

  1. 拓宽

    int -> long -> float -> double
    
  2. 拳击

    Integer -> Number -> Object
    
  3. a)扩大Varargs

    int... -> long... -> float... -> double...
    

    b)拳击然后Varargs

    Integer... -> Number... -> Object...
    

  4. 换句话说

       Varargs  [Last option]
          ^
          |
       Boxing   [Newer style, added in Java 1.5]
          ^
          |
       Widening [Older style, choosen by the compiler to support existing code]
    

    注意:

    • Boxing然后也允许Widening
    • Varargs然后不允许Boxing
    • Varargs被视为Wideningboxing
    • 之间的最后一个选项
    • 选择Widening then VarargsBoxing then Varargs。如果两种可能性都存在,则会导致模糊方法调用。

    f(new Integer(2))案例中的转化。根据规则Boxing,然后Widening

    Integer -> Number -> Object -> int -> long -> float -> double
    

    现在double

    旁边有两种可能性
    • 3.a)扩大Varargs(int...

    • 3.b)拳击然后Varargs(Integer...

    但两者都存在,因此导致不明确的方法调用。


    f(new Integer[]{3,4,5})

    的转化

    Integer...是直接匹配。 Varargs然后不允许Boxing

答案 2 :(得分:0)

VarargsBoxing都是在Java 5中引入的。随着Java 5出现了处理遗留代码的问题,其中编译器执行了扩展操作(例如,在有很长的情况下,编译器会选择长于整数,因为在Java 5之前允许将操作从int扩展到long,但由于varargs和Boxing处于同一级别(Java 5以后),编译器无法确定正确的类型。只需删除varargs并替换为数组,它会工作正常

Varargs和Boxing / Unboxing在组合使用时没有明确的偏好

答案 3 :(得分:-2)

......适用于可变数量的参数。你必须传递像f(1,2,3)这样的值,这就是错误的原因。