Case 1
static void call(Integer i) {
System.out.println(\"hi\" + i);
}
static void call(int i) {
System.out.println(\"hello\" + i);
This question has already been asked a number of times. The tricky part is that f(1, 2, 3)
is clearly passing int
's, so why can't the compiler pick the f(int...)
version? The answer must lie somewhere in the JLS, which I'm scratching my heads against
According to §15.12.2.4, both methods are applicable variable-arity method, so the next step is identifying the most specific one.
Unofortunately, §15.12.2.5 uses the subtype test Ti <: Si between f1(T1, .. Tn) and f2(S1, .. Sn) formal parameters to identify the target method, and since there is no subtype relationship between Integer
and int
, no one wins, because neither int :> Integer nor Integer :> int. At the end of the paragraph is stated:
The above conditions are the only circumstances under which one method may be more specific than another. [...]
A method m1 is strictly more specific than another method m2 if and only if m1 is more specific than m2 and m2 is not more specific than m1.
A method is said to be maximally specific for a method invocation if it is accessible and applicable and there is no other method that is applicable and accessible that is strictly more specific.
It is possible that no method is the most specific, because there are two or more methods that are maximally specific. In this case:
[...]
Otherwise, we say that the method invocation is ambiguous, and a compile-time error occurs.
Attached a blog post by Gilad Bracha (see exhibit 2), in turn linked in the bug report from the @Jayamhona's answer.
The compiler doesn't know which method should be called. In order to fix this, you need to cast the input parameters..
public static void main(String... args) {
call((int)10);
call(new Integer(10));
}
EDIT:
It is because the compiler tries to convert the Integer into int, Therefore, an implicit cast takes place prior to invocation of the call
method. So the compiler then looks for any methods by that name that can take ints. And you have 2 of them, so the compiler doesn't know which of both should be called.
Looks like it's related to bug #6886431, which seems to be fixed in OpenJDK 7.
Below is the bug description,
Bug Description:
When invoking a method with the following overloaded signatures, I expect an ambiguity error (assuming the arguments are compatible with both):
int f(Object... args);
int f(int... args);
javac treats the second as more specific than the first. This behavior is sensible (I prefer it), but is inconsistent with the JLS (15.12.2).
If more than one method can be applicable, than from the Java Language Specification we Choosing the Most Specific Method, paragraph 15.12.2.5
:
One variable arity member method named m
is more specific than another variable arity member method of the same name if either (<: means subtyping
):
Although primitive int
is autoboxed to wrapper Integer
, int[]
is not autoboxed to Integer[]
, than the first condition doesn't hold.
Second condition is almost the same.
There are also other conditions that do not hold, and then due to JLS:
we say that the method invocation is ambiguous, and a compile-time error occurs.
Finding the most specific method is defined in a very formal way in the Java Language Specificaion (JLS). I have extracted below the main items that apply while trying to remove the formal formulae as much as possible.
In summary the main items that apply to your questions are:
The third phase (§15.12.2.4) allows overloading to be combined with variable arity methods, boxing, and unboxing.
Integer...
or an int...
. So far so good. And the paragraph concludes:The most specific method (§15.12.2.5) is chosen among the applicable variable-arity methods.
m(a...)
is more specific than another arity method m(b...)
. In your use case with one parameter and no generics, it boils down to:
m(a...)
is more specific thanm(b...)
iifa <: b
, where<:
meansis a subtype of
.
It happens that int
is not a subtype of Integer
and Integer
is not a subtype of int
.
To use the JLS language, both call
methods are therefore maximally specific (no method is more specific than the other). In this case, the same paragraph concludes:
- If all the maximally specific methods have override-equivalent (§8.4.2) signatures [...] => not your case as no generics are involved and Integer and int are different parameters
- Otherwise, we say that the method invocation is ambiguous, and a compile-time error occurs.
NOTE
If you replaced Integer...
by long...
for example, you would have int <: long
and the most specific method would be call(int...)
*.
Similarly, if you replaced int...
by Number...
, the call(Integer...)
method would be the most specific.
*There was actually a bug in JDKs prior to Java 7 that would show an ambiguous call in that situation.
from JLS 15.12.2.2
JLS 15.12.2.2 Choose the Most Specific Method
IIf more than one method declaration is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specific method is chosen. The informal intuition is that one method declaration is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time type error.
neither of these methods can be passed to the other (the types for int[] and Integer[] arent related) hence the call is ambiguous