java methods method-overloading overloading variadic-functions

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:

  1. El ensanchamiento primitivo usa el argumento de método más pequeño posible
  2. El tipo de contenedor no se puede ampliar a otro tipo de contenedor
  3. Puede Box de int a Integer y ensanchar a Object pero no a Long
  4. La ampliación supera al boxeo, el boxeo supera a los var-args.
  5. Puedes Boxear y luego Widen (Un int puede convertirse en Object vía Integer)
  6. No puede ampliar y luego cuadro (un int no puede ser largo)
  7. 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