Ambiguous overloaded java methods with generics and varargs

I am trying to understand how java deals with ambiguities in function calls. In the following code, the method call is ambiguous, but method2 not !!!.

I feel both are ambiguous, but why does this compile when I comment on the method call? Why is method2 not ambiguous?

 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 appeared in the comments: a number of IDEs say they are so ambiguous - IntelliJ and Netbeans. However, it compiles just fine from the / maven command line.

+46
java generics variadic-functions
May 17 '12 at 19:25
source share
1 answer

An intuitive way of checking whether method1 more specific than method2 is to see if method1 can be implemented by calling method2 with the same parameters

 method1(params1){ method2(params1); // if compiles, method1 is more specific than method2 } 

If varargs exist, we may need to deploy vararg so that the 2 methods have the same number of parameters.

Check the first two method() in your example

 <K> void method_a(K arg, Object... otherArgs) { method_b(arg, otherArgs); //ok L1 } <K> void method_b(Object arg, Object... otherArgs) { // extract 1 arg from vararg method_a(arg, otherArgs); //ok L2 } 

(return types are not used in determining specificity, therefore they are omitted)

Both are compiled, so each of them is more specific than the other, therefore ambiguity. The same goes for your method2() s, they are more specific to each other. Therefore, the call to method2() ambiguous and should not be compiled; otherwise it is a compiler error.




So what the spec says; but is that right? Of course, method_a looks more specific than method_b . In fact, if we have a specific type instead of K

 void method_a(Integer arg, Object... otherArgs) { method_b(arg, otherArgs); // ok } void method_b(Object arg, Object... otherArgs) { method_a(arg, otherArgs); // error } 

then only method_a more specific than method_b , and not vice versa.

The discrepancy arises from type inference magic. L1 / L2 calls a generic method with no explicit type arguments, so the compiler tries to print the type arguments. The purpose of a type determination algorithm is to find type arguments that compile code! Not surprisingly, L1 and L2 compile. L2 actually is to be this.<Object>method_a(arg, otherArgs)

Type input tries to guess what the programmer wants, but the assumption must be wrong sometimes. Our real intention is actually

 <K> void method_a(K arg, Object... otherArgs) { this.<K>method_b(arg, otherArgs); // ok } <K> void method_b(Object arg, Object... otherArgs) { this.<K>method_a(arg, otherArgs); // error } 
+14
May 18 '12 at 15:06
source share
β€” -



All Articles