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 ):
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.
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.
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í ).