parametros - Métodos java sobrecargados ambiguos con genéricos y varargs
java parametros indefinidos (1)
Una forma intuitiva de comprobar si method1
es más específico que method2
es ver si method1
puede implementarse invocando method2
con los mismos parámetros
method1(params1){
method2(params1); // if compiles, method1 is more specific than method2
}
Si hay varargs, podemos necesitar expandir un vararg para que 2 métodos tengan el mismo número de params.
Vamos a verificar los primeros dos method()
en tu ejemplo
<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
}
(los tipos de devolución no se utilizan para determinar la especificidad, por lo que se omiten)
Ambos compilan, por lo tanto, cada uno es más específico que el otro, de ahí la ambigüedad. Lo mismo ocurre con su method2()
s, son más específicos que el otro. Por lo tanto, la llamada a method2()
es ambigua y no debe compilarse; de lo contrario, es un error del compilador.
Entonces eso es lo que dice la especificación; pero es correcto? Ciertamente, method_a
parece más específico que method_b
. En realidad, si tenemos un tipo concreto en lugar de 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
}
entonces solo method_a
es más específico que method_b
, no al revés.
La discrepancia surge de la magia de la inferencia de tipo. L1
/ L2
llama a un método genérico sin argumentos de tipo explícito, por lo que el compilador intenta inferir los argumentos de tipo. El objetivo del algoritmo de inferencia de tipo es encontrar argumentos de tipo tales que compile el código . No es de extrañar que L1 y L2 compilen. L2 es realmente inferir que es this.<Object>method_a(arg, otherArgs)
La inferencia tipo intenta adivinar lo que el programador quiere, pero la suposición debe ser incorrecta a veces. Nuestra verdadera intención es en realidad
<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
}
Estoy tratando de entender cómo Java maneja las ambigüedades en las llamadas a funciones. En el siguiente código, la llamada al method
es ambigua, pero method2
no lo es !!!.
Siento que ambos son ambiguos, pero ¿por qué compila esto cuando comento la llamada al method
? ¿Por qué el method2
no es ambiguo también?
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 );
}
}
EDITAR: Esto surgió en los comentarios: varios IDE informan ambos como ambiguos: IntelliJ y Netbeans hasta el momento. Sin embargo, compila muy bien desde la línea de comandos / maven.