java methods variadic-functions

java - Métodos varargs ambiguos



methods variadic-functions (4)

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

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"); } }

¿Alguien puede decirme la razón por la cual 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 del boxeo y el desempaquetado, la llamada foo(1) no habría sido ambigua. Para garantizar la compatibilidad con versiones anteriores de Java, la llamada sigue siendo inequívoca. Por lo tanto, la primera fase de resolución de sobrecarga no permite el boxeo, el desempaquetado o la invocación de aridad variable, que se introdujeron 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 el boxeo está permitido, 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 compilación pasando el 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 del método de aridad variable. Si no se encuentra ningún método aplicable durante esta fase, el procesamiento continúa a 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 aún 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, el procesamiento continúa a la tercera fase.

  3. La tercera fase (§15.12.2.4) permite que la sobrecarga se combine con métodos de arity variables, boxing y unboxing.

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 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 programació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 alguno de los siguientes es verdadero:

...

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

En su caso, tiene dos métodos no genéricos que son aplicables por invocación de aridad variable (es decir, ambos tienen varargs). Para que se elija uno de los métodos cuando se llama 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 cuando llame al method(1) .


La diferencia entre int e Integer es que Integer es un tipo de objeto. Puede usarlo en situaciones como encontrar el número máximo de tipo int o compararlo 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/


Porque son ambiguos. De acuerdo con JLS, puede hacer ensanchamiento, boxeo o boxeo-luego-ensanchamiento. En su ejemplo, hay 2 parámetros de métodos que se pueden encajonar / desempaquetar entre sí. En tiempo de compilación, aunque no es visible debido a varargs , que siempre no estaban del todo claros en Java.

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