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?
It is now clear that the method var(int...)
is selected and not var(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
5.3. Method Invocation Conversion
Method invocation conversion is applied to each argument value in a method or constructor invocation (§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 allow the use of _one of_ the following:
- an identity conversion (§5.1.1)
- a widening primitive conversion (§5.1.2)
- a widening reference conversion (§5.1.5)
- a boxing conversion (§5.1.7) optionally followed by widening reference conversion
- an unboxing conversion (§5.1.8) optionally followed by a widening primitive conversion.
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 an int
and then apply a boxing conversion on the same argument from int
to Integer
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:
The third phase (§15.12.2.4) allows overloading to be combined with variable arity methods, boxing, and unboxing.
Section 15.12.4 is quite complicated, but the rules that apply here are:
So..
var
with (byte, Integer)
var(Integer...)
byte
, to Integer
(the declared type of the argument in the method)byte
to an Integer
directly - it cannot do two steps.var(Integer...)
var(int...)
byte
to an int
using a widening primitive conversion. That's a check mark.Integer
, it sees that JLS 5.3 allows the compiler to convert it to an int
using an unboxing conversion. So that's also a check mark.var(int...)
is a good match.var
, so var(int...)
is the only applicable method. The compiler will now generate code to do the necessary conversions and invoke that method.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With