The above code gives compiler error of ambiguous call to go() method. When the var-arg are removed from the parameters of both versions of go() method, then it compiles fine. Ambiguous call comes only with var-arg. Can anyone explain this for me?
This is a difficult question, it requires some digging in the Java Language Specification to find out why it works like this.
First of all I replaced "Integer..." by "int..." in your first go() method; it still works the same (error with the varargs dots, no error without).
When there are multiple methods that match the call, Java normally chooses the most specific method. Section 18.104.22.168 of the JLS explains how this works for methods with a fixed number of arguments and for methods with a variable number of arguments ("variable arity" methods).
This paragraph in the JLS is hard to read and understand because of the formal language and symbols used. The symbol "<:" is explained in section 4.10. If I understand it correctly, the notation "T <: S" basically means that T is a subtype of S, or T is the same type as S. Section 4.10.1 says that long should be regarded as a direct supertype of int, so that means int <: long is true.
Now back to 22.214.171.124. It explains the rules that say when one method is more specific than another method, based on the argument types. When I read this carefully my conclusion is that both without and with the varargs dots, the "int..." version of the go() method is the most specific method. That means that in both cases the compiler should call the "int..." method.
So, either I am reading the JLS wrong or this is a bug in the Java compiler.
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?
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.
Now that the bug database is back online, we can read the bug report and see that the two overloads in the report are foo(int... i) and foo(double... d). Thus, both the varargs are primitive types, and the compiler should be able to determine that int is a subtype of double, therefore the foo(int... i) overload should be more specific - but the compiler's not saying that.
Thus, the bug report is analogous to Jesper's modified version of the problem above, where he changed Integer... to int.... That version of the problem does indeed show a bug in the compiler.
The bug report is not similar enough to Ansar's original problem though. In that version Integer is not a subtype of long, and long is not a subtype of int - therefore neither overload is more specific than the other, and there is no most specific method. In Ansar's original code, the compiler is correct; the code is ambiguous according to the specification. It's not a bug.
Thanks for your valuable comments. What I had in my mind while creating the originally posted scenario was the concept of Boxing. The question was that, Is the compiler intelligent enough to box Integer to int before checking for the most specific version of the overloaded method? and the answer was YES. Then I introduced var-args in the parameters. This is where the problem came.
The above code gives compiler error of ambiguous call to go() method. When the var-arg are removed from the parameters of both versions of go() method, then it compiles fine. Ambiguous call comes only with var-arg. Can anyone ...