Varargs Java Ambiguous Call
methods method-overloading (2)
Estoy un poco confundido acerca de los métodos varargs de Java:
public static int sum(int ...a) {
return 0;
}
public static double sum(double ...a) {
return 0.0;
}
Cuando intenté invocar
sum()
sin pasar ningún argumento, se invocó la versión
int
del método.
No entiendo por qué;
normalmente el compilador debe generar un error.
Por el contrario, el siguiente código genera un error de compilación cuando intento invocar la
sum
sin ningún argumento:
public static int sum(int ...a) {
return 0;
}
public static boolean sum(boolean ...a) {
return true;
}
Como se menciona en esta respuesta , hay reglas que se siguen al seleccionar qué método sobrecargado usar.
Citar:
- El ensanchamiento primitivo usa el argumento de método más pequeño posible
- El tipo de contenedor no se puede ampliar a otro tipo de contenedor
- Puede Box de int a Integer y ensanchar a Object pero no a Long
- La ampliación supera al boxeo, el boxeo supera a los var-args.
- Puedes Boxear y luego Widen (Un int puede convertirse en Object vía Integer)
- No puede ampliar y luego cuadro (un int no puede ser largo)
- No puede combinar var-args, tanto con ensanchamiento como con boxeo.
(Redefinamos la regla 1 de esta manera: "El ensanchamiento primitivo usa el argumento del método más específico posible").
Entonces, con estas reglas en mente, podemos tener una idea de lo que está sucediendo aquí:
Según la regla número uno, el ensanchamiento primitivo usa el argumento del método más específico posible.
Dado que un
int
está representado por un número no decimal (por ejemplo,
1
) y un
double
está representado por un número decimal con una precisión de 32 bytes más que la de un
float
(por ejemplo,
1.0
), podemos decir que
int
s son "menores que "o" más pequeño que "
double
s, y por esa lógica,
int
s puede ser" promovido "a
double
sy
double
s puede ser" degradado "a
int
s.
En pocas palabras, una primitiva que se puede ampliar a otra primitiva (por ejemplo,
int
->
float
->
double
) es
más específica
que otra.
Por ejemplo, un
int
es
más específico
que un
double
porque
1
puede promoverse a
1.0
.
Cuando no pasó ningún argumento a estos métodos de vararg sobrecargados del mismo nombre, ya que el retorno es efectivamente el mismo (0 y 0.0 respectivamente), el compilador elegiría usar el método que toma un vararg de tipo
int
ya que es
más específico
Entonces, cuando introdujo estos mismos métodos que toman
int
sy
boolean
s (tipos que no se pueden ampliar entre sí) respectivamente, el compilador ahora no puede elegir un método para usar, ya que
int
s no se puede "promocionar" o "degradar "como
int
s,
float
sy
double
s.
Por lo tanto, arrojará un error de compilación.
Espero que esto te ayude a entender lo que está sucediendo.
La regla general que se aplica aquí es la siguiente: si la firma de un método es estrictamente más específica que la otra, entonces Java la elige sin error.
Intuitivamente, una firma de método es más específica si pudiera eliminarla por completo y la otra, menos específica, sería aplicable a cada invocación existente.
Cuando se presenta una elección entre la
sum(int... args)
firmas
sum(int... args)
y la
sum(double... args)
, la
sum(int... args)
firmas
sum(int... args)
es más específica porque cualquier invocación de ese método también podría pasarse para
sum(double... args)
aplicando una conversión de ampliación.
Lo mismo no es válido para un método de
sum(boolean... args)
, que no se puede convertir de manera similar.
Especificación del lenguaje Java, versión SE 8:
15.12. Método Expresiones de invocación
15.12.2.5. Elegir el método más específico
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, y m1 y m2 son aplicables por invocación estricta o flexible, y donde m1 tiene tipos de parámetros formales S1, ..., Sn y m2 tiene tipos de parámetros formales T1, ..., Tn, el tipo Si es más específico que Ti para el argumento ei para todo i (1 ≤ i ≤ n, n = k).
...
Un tipo S es más específico que un tipo T para cualquier expresión si S <: T (§4.10).
4.10. Subtipificación
4.10.1. Subtipificación entre tipos primitivos
doble> 1 flotador
flotador> 1 largo
largo> 1 int