java - ¿Por qué dos métodos con firma(primitivo, envoltorio) y(primitivo, primitivo) hacen que el método llamado(envoltorio, primitivo) sea ambiguo?
jdk1.6 (3)
Es solo un ejercicio, pero no puedo entender la ambigüedad:
private static void flipFlop(String str, int i, Integer iRef) {
System.out.println(str + "ciao");
}
private static void flipFlop(String str, int i, int j) {
System.out.println(str + "hello");
}
public static void main(String[] args) {
flipFlop("hello", new Integer(4), 2004);
}
Dice:
El método flipFlop (String, int, Integer) es ambiguo para el tipo Test
Habría adivinado que el segundo argumento se habría flipFlop
a int y, por lo tanto, el segundo método flipFlop
habría sido la elección.
El segundo argumento de 2004
que es un int
, también se aplicaría a un Integer
debido auto-boxing , por eso el compilador no puede decidir qué método usar.
Muy bien, he echado un vistazo más de cerca al JLS y creo que esto debería aclarar cualquier duda que pueda tener.
Este es el problema original:
public class Main {
private static void flipFlop(int i, Integer iRef) {
System.out.println("Method 1");
}
private static void flipFlop(int i, int j) {
System.out.println("Method 2");
}
public static void main(String[] args) {
flipFlop(new Integer(4), 2004);
}
}
Como se ha señalado en la otra respuesta: esto falla porque el compilador no puede decidir qué sobrecarga utilizar.
Sin embargo, puedes pensar que esto no tiene ningún sentido. El compilador puede decidir bien en esta situación qué método debería usar:
public class Main {
private static void flipFlop(Integer y) {
System.out.println("ciao");
}
private static void flipFlop(int j) {
System.out.println("hello");
}
public static void main(String[] args) {
flipFlop(new Integer(6));
flipFlop(6);
}
}
La racionalidad nos dice que cuando tienes valores X
+ Y
y dos métodos que toman respectivamente Y
+ X
e Y
+ Y
y sabes que X
e Y
son intercambiables, esto significaría que el último método es más específico.
La diferencia entre estos dos se describe en el JLS. He proporcionado todo el flujo de trabajo a continuación, pero lo que importa es esto:
Primero, el compilador examinará los métodos con una firma igual mientras prohíbe el boxeo / desempaquetado. En nuestro segundo ejemplo, esto no causa ningún problema, pero en nuestro primer ejemplo no devuelve un método satisfactorio, ya que ninguno de ellos toma un Integer
como primer parámetro.
Cuando eso falló, el compilador pasa al segundo paso donde permite el boxeo / desempaquetado. Esto debería solucionar el problema que tuvimos con el primer parámetro, pero ahora causa ambigüedad con el segundo parámetro, ya que ahora es incierto si se está refiriendo a la sobrecarga que usa un int
o al que usa un Integer
.
En última instancia, esto resulta en una llamada de método ambiguo.
15.12.2. Tiempo de compilación, paso 2: determinar la firma del método
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 invocación del 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.
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 hasta la tercera fase.
Si se han identificado varios métodos aplicables durante una de las tres fases de las pruebas de aplicabilidad, se elige el más específico, como se especifica en la sección §15.12.2.5 .
Se dice que un método es máximo específico para una invocación de método si es accesible y aplicable y no hay otro método que sea aplicable y accesible que sea estrictamente más específico.
Es posible que ningún método sea el más específico, porque hay dos o más métodos que son máximamente específicos. En este caso:
Si todos los métodos máximamente específicos tienen firmas de anulación equivalente ( §8.4.2 ), entonces: (... algunas reglas para decidir quién ha elegido ...)
De lo contrario, decimos que la invocación del método es ambigua y se produce un error en tiempo de compilación.
Si le gusta la lectura fascinante, aquí está la parte relevante de la especificación del lenguaje Java que describe cómo se resuelven los métodos.
Pero, básicamente, su tercer argumento puede interpretarse como una envoltura primitiva o autoboxed, y el compilador no puede averiguar lo que quiere. Ambos métodos son " máximamente específicos " para usar la terminología JLS.