Now it’s clear that the var(int...) method is selected, and not var(Integer...) .
The reason is that only certain conversions are allowed to be applied, and this can be only one of these conversions from the list, and not the conversion chain. The java compiler is not allowed to convert the primitive primitive first, and then convert to boxing.
It is listed in the Java Language Specification in Section 5.3.
5.3. Method call conversion
Conversion of a method call is applied to each argument value into a method or constructor call (§8.8.7.1, §15.9, §15.12): the type of the argument expression must be converted to the type of the corresponding parameter.
Method invocation contexts let you use _one of_ the following:
- identity transformation (§5.1.1)
- extension of primitive conversion (§5.1.2)
- extension of referenced conversion (§5.1.5)
- box conversion (§5.1.7), optionally followed by link extension conversion
- transformation for unpacking (clause 5.1.8), followed by extension of the primitive transformation.
The only option for the compiler:
- extension of primitive conversion by first argument
- unboxing conversion in second argument
This turns (byte, Integer) into (int, int) .
It cannot first transfer the first byte argument to int , and then apply the box transform on the same argument from int to Integer , because two conversions in the sequence are not allowed.
Let's go back to one step to find out how the compiler chooses which overloaded method to call. This is described in JLS 15.12.2 . (12.15.1 describes how to find a class or interface to search, but we already know that we want to call a static method in the Main class)
The first two phases that the compiler looks through to select the correct overloaded method do not apply to variable argument methods ("arity variable"), but in the third step:
The third stage (§15.12.2.4) allows you to combine overloading with the methods of the arity variable, boxing and unpacking.
Section 15.12.4 is rather complicated, but the rules applicable here:
- first apply the rules for arguments without arity variable (not applicable in your case)
- each variable argument in the call must be converted by converting the method call (the piece that I copied above) to the type of the variable argument declaration
So..
- you are trying to call a method named
var with (byte, Integer) - the compiler is looking at your
var(Integer...) method var(Integer...) - he asks: can I convert the first argument,
byte , to Integer (the declared type of the argument in the method) - he looks at the rules in JLS 5.3. He can apply only one of the transformations from list 5. None of them can directly convert
byte to Integer - he cannot perform two steps. - So, the compiler decides that it cannot select
var(Integer...) - then it looks at your other method,
var(int...) - According to JLS 5.3, it can convert your first argument,
byte to int , using extended primitive conversion. This is a check mark. - Turning to the second argument, your
Integer , he sees that JLS 5.3 allows the compiler to convert it to int using unboxing conversion. So also a tick. - This was the last argument, so
var(int...) is a good match. - Now the compiler goes over to find out if there are more methods matching your call. If this is more, this will result in an ambiguous call error.
- But there are no more methods named
var , so var(int...) is the only applicable method. Now the compiler will generate code to perform the necessary transformations and call this method.