Varambs Java Ambiguous Call

Je suis un peu confus au sujet des méthodes varargs de Java:

public static int sum(int ...a) { return 0; } public static double sum(double ...a) { return 0.0; } 

Lorsque j’ai essayé d’appeler sum() sans passer aucun argument, la version int de la méthode a été appelée. Je ne comprends pas pourquoi; normalement, le compilateur doit générer une erreur.

En revanche, le morceau de code suivant génère une erreur de compilation lorsque j’essaie d’appeler sum sans aucun argument:

 public static int sum(int ...a) { return 0; } public static boolean sum(boolean ...a) { return true; } 

La règle générale qui s’applique ici est la suivante: si une signature de méthode est ssortingctement plus spécifique que l’autre, alors Java le choisit sans erreur.

Intuitivement, une signature de méthode est plus spécifique si vous pouvez la supprimer entièrement et l’autre, moins spécifique, serait applicable à chaque invocation existante.

Lorsqu’il est présenté avec un choix entre les signatures sum(int... args) et sum(double... args) , la sum(int... args) la signature sum(int... args) est plus spécifique car toute invocation de cette méthode pourrait également être transmise faire la sum(double... args) en appliquant une conversion élargie. La même chose ne vaut pas pour une méthode sum(boolean... args) , qui ne peut pas être convertie de manière similaire.

Spécification du langage Java, version SE 8:

15.12. Expressions d’invocation de méthode

15.12.2.5. Choisir la méthode la plus spécifique

Le langage de programmation Java utilise la règle selon laquelle la méthode la plus spécifique est choisie.

Une méthode applicable m1 est plus spécifique qu’une autre méthode applicable m2, pour une invocation avec les expressions d’argument e1, …, ek, si l’une des conditions suivantes est vraie:

  • m2 n’est pas générique, et m1 et m2 sont applicables par invocation ssortingcte ou lâche, et où m1 a les types de parameters formels S1, …, Sn et m2 ont les types de parameters formels T1, …, Tn, le type Si est plus spécifique à Ti pour l’argument ei pour tout i (1 ≤ i ≤ n, n = k).

Un type S est plus spécifique qu’un type T pour toute expression si S <: T (§4.10).


4.10. Sous-typage

4.10.1. Sous-typage parmi les types primitifs

double> 1 flotteur

flotteur> 1 long

long> 1 int

Comme mentionné dans cette réponse , certaines règles sont suivies lors de la sélection de la méthode surchargée à utiliser.

Citer:

  1. L’élargissement primitif utilise le plus petit argument de méthode possible
  2. Le type de wrapper ne peut pas être élargi à un autre type de wrapper
  3. Vous pouvez Box de int à Integer et élargir à Object mais non à Long
  4. L’élargissement bat Boxing, la boxe bat Var-Args.
  5. Vous pouvez Box puis Widen (Un int peut devenir Object via Integer)
  6. Vous ne pouvez pas élargir puis Box (un int ne peut pas devenir long)
  7. Vous ne pouvez pas combiner var-args, à la fois avec l’ élargissement et la boxe.

(Redéfinissons la règle 1 comme suit: “L’élargissement primitif utilise l’argument de méthode le plus spécifique possible.”)

Avec ces règles en tête, nous pouvons avoir une idée de ce qui se passe ici:

Selon la règle numéro un, l’élargissement primitif utilise l’argument de méthode le plus spécifique possible. Etant donné qu’un int représente un nombre non décimal (par exemple 1 ) et qu’un double est représenté par un nombre décimal avec une précision de 32 octets de plus que celui d’un float (par exemple 1.0 ), on peut dire que int est “inférieur à “ou” plus petit que “s double , et par cette logique, int s peut être” promu “à double s et double s peut être” rétrogradé “à int s.

En d’autres termes, une primitive pouvant être élargie à une autre primitive (par exemple, int -> float -> double ) est plus spécifique qu’une autre. Par exemple, un int est plus spécifique qu’un double car 1 peut être promu à 1.0 .

Lorsque vous ne transmettez pas d’arguments à ces méthodes vararg surchargées du même nom, puisque le retour est effectivement le même (0 et 0.0 respectivement), le compilateur choisirait d’utiliser la méthode qui prend un vararg de type int puisqu’il est plus spécifique

Ainsi, lorsque vous avez introduit ces mêmes méthodes qui prennent respectivement int s et boolean s (types qui ne peuvent pas être élargis l’un à l’autre), le compilateur ne peut plus choisir une méthode puisque int s ne peut pas être “promu” ou “rétrogradé” “comme int s, float s et double s. Par conséquent, il générera une erreur de compilation.

J’espère que cela vous aide à comprendre ce qui se passe.