The rules for selecting the correct overloaded method are as follows:
- Primitive widening uses the smallest method argument possible
- Wrapper type cannot be widened to another Wrapper type
- You can Box from int to Integer and widen to Object but no to Long
- Widening beats Boxing, Boxing beats Var-args.
- You can Box and then Widen (An int can become Object via Integer)
- You cannot Widen and then Box (An int cannot become Long)
- You cannot combine var-args, with either widening or boxing
Have a look at that last rule. You can not combine widening or boxing with variable length arguments. That means that the types can not be manipulated in any way and you have to perform the comparison as is. int
and long
can be compared, no problem and the compiler can deduce that int
is the smaller of the two. As per the first rule, it will go for the smallest method argument possible, hence it has worked out the correct (and only) route to a method.
However, when you get to boolean
and int
, there exists no comparison method between the two because of Java's strong typing. With no knowledge of which type is smallest, the compiler has absolutely no clue which method you mean.
More Visual Example
Let's take it step by step from the perspective of the compiler. First, with int
and long
.
int and long
Step 1 - Checking if the parameters match any arguments and if so, which one it matches exactly
Well, varargs
means that you can pass 0
to many arguments. In this case, you've elected to pass 0
arguments, hence your call matches both the int
type and the long
type.
Step 2 - Attempt to autobox or widen. This should help it work out which one to go for
You're using varargs, so the compiler knows it can't do this, as per the final rule.
Step 3 - Attempt to work out which type is smallest
The compiler is able to compare the type int
with the type long
. From this, it works out that the int
is the smallest type.
Step 4 - Make the call
With the knowledge that int
is the smallest type, it then passes the value to the method for execution.
Okay, and now let's do the same thing with boolean
and int
.
boolean and int
Step 1 - Checking if the parameters match any arguments and if so, which one it matches exactly
Same story. You've passed nothing so match both arguments.
Step 2 - Attempt to autobox or widen. This should help it work out which one to go for
As above, you're not permitted to do this because you used varargs.
Step 3 - Attempt to work out which type is smallest
This is the crucial difference. Here, the types are not comparable. This means that the compiler doesn't know which method you want to call by your parameters or by the smallest type. Ergo, it has been unable to work out the correct route.
Step 4 - Make the call
Without the knowledge of which method to call, it can not continue execution and throws the appropriate exception.