Please, could you help me to understand why compilation of first call of testVargArgsAutoboxingPriority fails?
In case of second call compiler is able to select proper method by preferring primitive (first parameter) to Object but after varargs parameter addition compiler is not able to make the selection any more.
Fail message is
\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
Full code listing is
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 )
{}
}
The answer lies in the JLS - 15.12.2. Compile-Time Step 2: Determine Method Signature and on @TheNewIdiot answer above. Here is a more detailed explanation:
For the methods:
private static void testVargArgsAutoboxingPriority( Integer b ) {}
private static void testVargArgsAutoboxingPriority( int b ) {}
The compiler needs only the first phase in order to know which method to call. And in the first phase it's not mixing boxed and primitive types.
But the methods:
private static void testVargArgsAutoboxingPriority( Integer b, boolean... c ) {}
private static void testVargArgsAutoboxingPriority( int b, boolean... c ) {}
contains varargs arguments and the compiler needs to get to the third phase trying to distinguish between them. But in the third phase is not able anymore to make the distinction between a boxed type and its corresponding primitive type.
As per JLS 15.12.2 Compile-Time Step 2: Determine Method Signature.
The process of determining applicability begins by determining the potentially applicable methods (§15.12.2.1).
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.
This guarantees that any calls that were valid in the Java programming language before Java SE 5.0 are not considered ambiguous as the result of the introduction of variable arity methods, implicit boxing and/or unboxing. However, the declaration of a variable arity method (§8.4.1) can change the method chosen for a given method method invocation expression, because a variable arity method is treated as a fixed arity method in the first phase. For example, declaring m(Object...) in a class which already declares m(Object) causes m(Object) to no longer be chosen for some invocation expressions (such as m(null)), as m(Object[]) is more specific.
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.
This ensures that a method is never chosen through variable arity method invocation if it is applicable through fixed arity method invocation.
The third phase (§15.12.2.4) allows overloading to be combined with variable arity methods, boxing, and unboxing.