当重载编译器只在varargs参数存在的情况下不喜欢原语到Object

时间:2013-07-13 17:53:57

标签: java overloading primitive variadic-functions autoboxing

拜托,您能帮助我理解为什么第一次调用testVargArgsAutoboxingPriority的编译失败了吗?

在第二次调用的情况下,编译器可以通过优先选择原语(第一个参数)来选择正确的方法,但是在varargs参数添加后,编译器无法再进行选择。

失败消息

\jdk1.6.0_45\bin\javac.exe ocjp6/AutoBoxingOldStyleVarargsPriority.java
ocjp6\AutoBoxingOldStyleVarargsPriority.java:7: reference to testVargArgsAutoboxingPriority is ambiguous, both method testVargArgsAutoboxing
Priority(java.lang.Integer,boolean...) in ocjp6.AutoBoxingOldStyleVarargsPriority and method testVargArgsAutoboxingPriority(int,boolean...)
in ocjp6.AutoBoxingOldStyleVarargsPriority match
      testVargArgsAutoboxingPriority( 5, true ); // the line compilation fails
      ^
1 error

完整的代码列表是

package ocjp6;

public class AutoBoxingOldStyleVarargsPriority
{
   public static void main( final String[] args )
   {
      testVargArgsAutoboxingPriority( 5, true ); // the line compilation fails
      testVargArgsAutoboxingPriority( 5 );
   }

   private static void testVargArgsAutoboxingPriority( Integer b, boolean... c )
   {}
   private static void testVargArgsAutoboxingPriority( int b, boolean... c )
   {}

   private static void testVargArgsAutoboxingPriority( Integer b )
   {}
   private static void testVargArgsAutoboxingPriority( int b )
   {}
}

2 个答案:

答案 0 :(得分:3)

答案在于JLS - 15.12.2. Compile-Time Step 2: Determine Method Signature以及@TheNewIdiot上面的回答。这是一个更详细的解释:

方法:

private static void testVargArgsAutoboxingPriority( Integer b ) {}
private static void testVargArgsAutoboxingPriority( int b ) {}

编译器只需要第一阶段就可以知道要调用哪个方法。在第一阶段,它不是混合盒装和原始类型。

但是方法:

private static void testVargArgsAutoboxingPriority( Integer b, boolean... c ) {}
private static void testVargArgsAutoboxingPriority( int b, boolean... c ) {}

包含varargs参数,编译器需要进入第三阶段,试图区分它们。但是在第三阶段不再能够区分盒装类型和相应的基元类型。

答案 1 :(得分:2)

根据JLS 15.12.2 Compile-Time Step 2: Determine Method Signature

  

确定适用性的过程首先要确定可能适用的方法(§15.12.2.1)。

     

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

     

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

     

这保证了在Java SE 5.0之前在Java编程语言中有效的任何调用都不会被认为是引入变量arity方法,隐式装箱和/或取消装箱的结果。但是,变量arity方法(第8.4.1节)的声明可以更改为给定方法方法调用表达式选择的方法,因为变量arity方法在第一阶段被视为固定arity方法。例如,在已声明m(Object)的类中声明m(Object ...)会导致不再为某些调用表达式(例如m(null))选择m(Object),因为m(Object [] )更具体。

     

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

     

这确保了如果通过固定的arity方法调用适用,则永远不会通过变量arity方法调用选择方法。

     

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