I know that this problem discussed many times but I don't understand anyway.
Research this code:
public class Main {
public static void var(Integer x, int y) {
System.out.println("Integer int");
}
public static void var(int... x) {
System.out.println("int... x");
}
public static void var(Integer... x) {
System.out.println("Integer...");
}
public static void main(String... args) {
byte i = 0;
Integer i2 = 127;
var(i, i2);
}
}
In my brain following rule:
widening
boxing
boxing+varargs
According this rule I make next actions
1.byte wides to int
Now I have int
Integer
and there are exist method takes Integer
and int
2.make boxing
Hence. int
-> Integer
and Integer
-> int
arguments
I think that arguments are applicable and expected to see
Integer int
in output.
But I see
int ...
why?
Java can only do "box and wide" not "wide and box". For example,
So, in your given methods, first argument byte already fails the two Integer methods. So, only int... is applicable.
I wrote the following class for demo:
It is now clear that the method
var(int...)
is selected and notvar(Integer...)
.The reason is that only certain conversions are allowed to be applied, and it can only be one of these conversions from the list, not a chain of conversions. The java compiler is not allowed to do a widening primitive conversion first, and then a boxing conversion.
It's specified in the Java Language Specification in section 5.3
The only option for the compiler is to do:
That turns
(byte, Integer)
into(int, int)
.It cannot first turn the first argument
byte
into anint
and then apply a boxing conversion on the same argument fromint
toInteger
because two conversions in sequence are not allowed.Let's go back one step to find out how the compiler selects which overloaded method to invoke. That is described in JLS 15.12.2. (15.12.1 describes how to find the class or interface to search, but we already know that we want to invoke a static method in class
Main
)The first two phases that a compiler goes through to select the right overloaded methoddo not apply to variable argument ("variable arity") methods, but the third phase does:
Section 15.12.4 is quite complicated, but the rules that apply here are:
So..
var
with(byte, Integer)
var(Integer...)
byte
, toInteger
(the declared type of the argument in the method)byte
to anInteger
directly - it cannot do two steps.var(Integer...)
var(int...)
byte
to anint
using a widening primitive conversion. That's a check mark.Integer
, it sees that JLS 5.3 allows the compiler to convert it to anint
using an unboxing conversion. So that's also a check mark.var(int...)
is a good match.var
, sovar(int...)
is the only applicable method. The compiler will now generate code to do the necessary conversions and invoke that method.