Métodos varargs ambiguos

Aquí hay un ejemplo de código que no se comstack:

public class Test { public static void main(String[] args) { method(1); } public static void method(int... x) { System.out.println("varargs"); } public static void method(Integer... x) { System.out.println("single"); } } 

¿Puede alguien decirme por qué estos métodos son ambiguos? Gracias de antemano.

Considere las firmas de método

 public static void foo(int a) 

y

 public static void foo(Integer a) 

Antes de boxear y desempaquetar, la llamada foo(1) no habría sido ambigua. Para garantizar la compatibilidad con versiones anteriores de Java, la llamada permanece inequívoca. Por lo tanto, la primera fase de la resolución de sobrecarga no permite el uso de boxeo, unboxing o invocación de aridad variable, que se introdujeron todos al mismo tiempo. La invocación de aridad variable es cuando se llama a un método varargs pasando una secuencia de parámetros para el último argumento (en lugar de una matriz).

Sin embargo, la resolución del method(1) para sus firmas de métodos permite el boxeo y el desempaquetado porque ambos métodos requieren una invocación de aridad variable. Como se permite el boxeo, se aplican ambas firmas. Normalmente cuando se aplican dos sobrecargas, se elige la sobrecarga más específica. Sin embargo, ninguna de sus firmas es más específica que la otra (porque ni int ni Integer son un subtipo de la otra). Por lo tanto, el method(1) llamada method(1) es ambiguo.

Puede hacer esta comstackción pasando new int[]{1} lugar.

Hay 3 fases utilizadas en la resolución de sobrecarga ( JLS 15.2.2 ):

  1. La primera fase (§15.12.2.2) realiza la resolución de sobrecarga sin permitir la conversión de boxeo o unboxing, o el uso de la invocación de método de aridad variable. Si no se encuentra ningún método aplicable durante esta fase, el procesamiento continúa hasta la segunda fase.

  2. La segunda fase (§15.12.2.3) realiza la resolución de sobrecarga al tiempo que permite el boxeo y el desempaquetado, pero todavía impide el uso de la invocación del método de aridad variable. Si no se encuentra ningún método aplicable durante esta fase, entonces el procesamiento continúa hasta la tercera fase.

  3. La tercera fase (§15.12.2.4) permite que la sobrecarga se combine con métodos de aridad variable, boxeo y desempaquetado.

En su ejemplo, ambos métodos son métodos de aridad variable, por lo que se aplica la tercera fase.

Ahora, dado que tenemos dos métodos para elegir, buscamos el método más específico.

JLS 15.12.2.5. Elegir el método más específico dice:

Si más de un método de miembro es accesible y aplicable a una invocación de método, es necesario elegir uno para proporcionar el descriptor para el envío del método en tiempo de ejecución. El lenguaje de progtwigción Java usa la regla de que se elige el método más específico.

Un método aplicable m1 es más específico que otro método aplicable m2, para una invocación con expresiones de argumento e1, …, ek, si cualquiera de los siguientes es verdadero:

m2 no es genérico, m1 y m2 son aplicables por invocación de aria variable, y donde los primeros k tipos de parámetros de aridad variables de m1 son S1, …, Sk y los primeros k tipos de parámetros de aridad variables de m2 son T1, … , Tk, el tipo Si es más específico que Ti para el argumento ei para todos los i (1 ≤ i ≤ k). Además, si m2 tiene parámetros k + 1, entonces el tipo de parámetro de aridad variable k + 1’th de m1 es un subtipo del tipo de parámetro de aridad variable k + 1’th de m2.

En su caso, tiene dos métodos no generics que son aplicables por invocación de aridad variable (es decir, ambos tienen varargs). Para que uno de los métodos se elija cuando llame al method(1) , uno de ellos debe ser más específico que el otro. En su caso, cada método solo tiene un parámetro, y para que uno de ellos sea más específico que el otro, el tipo de ese parámetro debe ser un subtipo del parámetro del otro método.

Como int no es un subtipo de Integer y Integer no es un subtipo de int , ninguno de sus métodos es más específico que el otro. Por lo tanto, el The method method(int[]) is ambiguous for the type Test Error de The method method(int[]) is ambiguous for the type Test .

Un ejemplo que funcionaría:

 public static void method(Object... x) { System.out.println("varargs"); } public static void method(Integer... x) { System.out.println("single"); } 

Como Integer es un subtipo de Object , el segundo método se elegiría al llamar al method(1) .

Porque son ambiguos. Según JLS, puede ampliar, boxear o encadenar y luego ampliar. En su ejemplo, hay 2 parámetros de métodos que pueden encajonarse / desempaquetarse entre sí. En tiempo de comstackción, aunque no es visible debido a varargs , que no siempre fueron absolutamente claros en Java.

Incluso Sun recomendó a los desarrolladores no sobrecargar los métodos varargs, había errores en el comstackdor relacionados con él ( ver aquí ).

La diferencia entre int e Integer es que Integer es un tipo de objeto. Se puede usar en situaciones como encontrar el número máximo de tipo int o comparar con enteros.

El objeto entero ya está asociado con métodos como el método de comparación:

 public static void method(int x, int y) { System.out.println(Integer.compare(x, y)); } 

Encuentre más en: http://docs.oracle.com/javase/7/docs/api/