Ansar, it looks like you have stumbled onto an issue that is more complicated than you are likely to encounter on the real exam. So while it may certainly be worthwhile to understand what's going on, it's the sort of thing that people can drive themselves crazy by worrying about it unnecessarily. The level of detail in this discussion is deeper than you need for the exam. If you follow the discussion and learn from it, excellent. But if not, it's best not to worry too much about it. This goes for everyone who may be reading this.
On to the discussion...
This is very strange. I believe I can explain why the code in Anshar's original post is ambiguous, but so far I don't see why Jesper's modified version is ambiguous.
The problem with Anshar's code is that the wrapper class Integer is not a subtype of the primitive type long, and long is not a subtype of Integer. Thus, neither method can be said to be more specific than the other, and thus both methods are maximally specific, which means the method call is ambiguous.
However, when Jesper changed Integer to int, int
is a subtype of long, and so it does seem that go(int... i) is more specific than go(long... i), and not vice versa. I don't know why the compiler complains that this is ambiguous. Perhaps we're both still missing something here.
Going back to the original question though:
[Ansar]: Ambiguous call comes only with var-arg. Can anyone explain this for me? This is because of the three phases of identifying potentially applicable methods, described generally in
JLS 15.12.2 and more specifically in
JLS 15.12.2.2,
JLS 15.12.2.3, and
JLS 15.12.2.4.
Basically, first the compiler looks for methods without considering varargs or boxing. If no methods are found, then it looks again, considering boxing but not varargs. And if still no methods are found, it looks once more, considering both boxing and varargs.
In your original code (with varargs), the compiler can't find any methods at all on the first two attempts, and then on the third attempt it considers varargs and finds two methods, neither of which is more specific than the others.
If you remove the varargs, then the important difference between the methods is that one requires boxing, and the other doesn't. Thus, on the compiler's first attempt to find applicable methods, without considering varargs or boxing, it finds exactly one method: go(long i). And since it finds that one method, the compiler doesn't
need to make a second or third attempt using boxing or varargs - it's done. It's found one applicable method, and that's good enough. If it had found two, it would have to decide which is more specific, but since it found only one, that's not an issue.