2012-05-17 36 views
46

Estoy tratando de comprender cómo Java maneja las ambigüedades en las llamadas a funciones. En el siguiente código, la llamada a method es ambigua, pero method2 no es !!!.Métodos java sobrecargados ambiguos con genéricos y varargs

Siento que ambos son ambiguos, pero ¿por qué compila esto al comentar 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 ); 
    } 
} 

EDIT: Este surgió en los comentarios: Un número de entornos de desarrollo informan tanto como ambigua - IntelliJ y Netbeans hasta ahora. Sin embargo, compila muy bien desde la línea de comandos/maven.

+0

Buena pregunta ... – Jivings

+0

tal vez sería aumentar el tiempo de compilación si java comprueba métodos utilizados – Joelmob

+0

@Joelmob siento la pregunta es ¿por qué 'method2' compilar cuando parece ser tan ambiguo como 'método'. – Jivings

Respuesta

14

una forma intuitiva para probar si method1 es más específica que method2 es ver si method1 se puede implementar mediante la invocación de method2 con los mismos parámetros

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

Si hay varargs, es posible que tengamos para expandir un vararg para que 2 métodos tengan el mismo número de params.

Vamos a ver los dos method() primeros s en su 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 
} 

(tipos de retorno no se utilizan en la determinación de especificidad, por lo que se omiten)

Tanto compilar, por lo tanto, cada uno es más específico que el otro, de ahí la ambigüedad. Lo mismo ocurre con sus method2() s, son más específicos que otros. Por lo tanto, la llamada a method2() es ambigua y no debe compilarse; de lo contrario, es un error del compilador.


Así que 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 sólo 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 de tipo Algoritmo de inferencia es encontrar argumentos de tipo tal que el código compila! No es de extrañar que L1 y L2 compilen. L2 es en realidad inferir que es this.<Object>method_a(arg, otherArgs)

La inferencia tipo intenta adivinar lo que el programador quiere, pero a veces la suposición debe ser incorrecta. Nuestra intención real 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 
} 
+0

Gracias por la prueba intuitiva ... pero no responde la pregunta. La pregunta es por qué la invocación del método ** falla ** pero el método2 ** pasa **. – Chip

+2

del análisis, la llamada a 'method2' es ambigua por falta del método * más específico *. por lo tanto, es un error del compilador. – irreputable

+0

Si deja eso en claro en la respuesta ... lo aceptaré. – Chip

Cuestiones relacionadas