I’m trying to understand how java deals with ambiguities in function calls. In the following code, the call to method is ambiguous, but method2 is not!!!.
I feel both are ambiguous, but why does this compile when I comment out the call to method? Why is method2 not ambiguous as well?
public class A {
public static <K> List<K> method(final K arg, final Object... otherArgs) {
System.out.println("I'm in one");
return new ArrayList<K>();
}
public static <K> List<K> method(final Object... otherArgs) {
System.out.println("I'm in two");
return new ArrayList<K>();
}
public static <K, V> Map<K, V> method2(final K k0, final V v0, final Object... keysAndValues) {
System.out.println("I'm in one");
return new HashMap<K,V> ();
}
public static <K, V> Map<K, V> method2(final Object... keysAndValues) {
System.out.println("I'm in two");
return new HashMap<K,V>();
}
public static void main(String[] args) {
Map<String, Integer> c = A.method2( "ACD", new Integer(4), "DFAD" );
//List<Integer> d = A.method(1, "2", 3 );
}
}
EDIT:
This came up in comments: A number of IDEs report both as ambiguous – IntelliJ and Netbeans so far. However, it compiles just fine from command-line/maven.
An intuitive way to test whether
method1is more specific thanmethod2is to see whethermethod1can be implemented by invokingmethod2with the same parametersIf there are varargs, we may need to expand a vararg so that 2 methods have same number of params.
Let’s check the first two
method()s in your example(return types are not used in determining specificity, so they are omitted)
Both compile, therefore each is more specific than the other, hence the ambiguity. Same goes for your
method2()s, they are more specific than each other. Therefore the call tomethod2()is ambiguous and shouldn’t compile; otherwise it’s a compiler bug.So that’s what the spec says; but is it proper? Certainly,
method_alooks more specific thanmethod_b. Actually if we have a concrete type instead ofKthen only
method_ais more specific thanmethod_b, not vice versa.The discrepancy arises from the magic of type inference.
L1/L2calls a generic method without explicit type arguments, so the compiler tries to infer the type arguments. The goal of type inference algorithm is to find type arguments such that the code compiles! No wonder L1 and L2 compile. L2 is actually infer to bethis.<Object>method_a(arg, otherArgs)Type inference tries to guess what the programmer wants, but the guess must be wrong sometimes. Our real intention is actually