63 votes

Pourquoi le compilateur préfère-t-il une surcharge int à une surcharge varargs pour un caractère?

Code

 public class TestOverload {

    public TestOverload(int i){System.out.println("Int");}
    public TestOverload(char... c){System.out.println("char");}

    public static void main(String[] args) {
        new TestOverload('a');
        new TestOverload(65);
    }
}
 

Sortie

 Int
Int
 

Est-ce comportement attendu? Si oui, alors pourquoi? Je m'attends à: char, Int

Remarque: j'utilise Java 8

81voto

Eran Points 35360

Méthodes avec varargs (...) ont la priorité la plus faible lorsque le compilateur détermine qui a surchargé la méthode à choisir. Par conséquent, TestOverload(int i) a été choisi plutôt qu' TestOverload(char... c) lorsque vous appelez TestOverload avec un seul char paramètre 'a', depuis un char peuvent être automatiquement promu int.

JLS 15.12.2 :

  1. La première phase (§15.12.2.2) effectue la résolution de surcharge , sans permettre de boxe ou unboxing de conversion, ou de l'utilisation de la variable d'arité l'invocation de méthode. Si non applicable méthode est trouvé au cours de cette phase ensuite, le traitement se poursuit pour la deuxième phase. Cela garantit que tous les appels qui étaient valables dans le langage de programmation Java langue avant de Java SE 5.0 ne sont pas considérés comme ambigus comme le résultat de l'introduction de la variable arité de méthodes implicites de la boxe et/ou unboxing. Toutefois, la déclaration d'une variable arity (§8.4.1) pouvez changer la méthode choisie pour une méthode donnée d'invocation de méthode l'expression, car une variable arity est traité comme un fixe arity dans la première phase. Par exemple, déclaration de m (...) dans une classe qui a déjà déclare m(Objet) causes m(Objet) ou pas plus être choisi pour certains invocation des expressions (tels que m(null)), m(Object[]) est plus spécifique.

  2. La deuxième phase (§15.12.2.3) effectue la résolution de surcharge, tout en permettant boxing et unboxing, mais encore s'oppose à l'utilisation de la variable d'arité de l'invocation de méthode. Si non applicable méthode est trouvé au cours de cette phase puis de continuer le traitement à la troisième phase. Ceci garantit qu'une méthode n'est jamais choisi par arité variable l'invocation de méthode, si elle est applicable par fixe arity invocation.

  3. La troisième phase (§15.12.2.4) permet de surcharger être combinée avec une variable d'arité de méthodes, de boxe, et unboxing.

EDIT:

Vous souhaitez forcer le compilateur à l'appel de l' TestOverload(char... c) constructeur, vous pouvez passer à l'appel du constructeur un char[] :

new TestOverload (new char[] {'a'});

36voto

Panther Points 1599

Oui, c'est un comportement attendu. La priorité pour l'appel de méthode qui va comme ceci :

  1. Widending
  2. Boxe
  3. Varargs

Ci-dessous est extrait de Java docs liés à même :-

Le processus de détermination de l'applicabilité commence par déterminer le potentiellement applicables méthodes (§15.12.2.1).

Le reste du processus est divisé en trois phases, pour assurer la compatibilité avec les versions du langage de programmation Java avant de Java SE 5.0. Les phases sont les suivantes:

La première phase (§15.12.2.2) effectue la résolution de surcharge, sans permettre de boxe ou unboxing de conversion, ou de l'utilisation de la variable d'arité de l'invocation de méthode. Si non applicable méthode est trouvé au cours de cette phase, puis de continuer le traitement à la deuxième phase.

Cela garantit que tous les appels qui étaient valables dans le langage de programmation Java avant de Java SE 5.0 ne sont pas considérés comme ambigus comme le résultat de l'introduction de la variable arité de méthodes implicites de la boxe et/ou unboxing. Toutefois, la déclaration d'une variable arity (§8.4.1) peut changer la méthode choisie pour une méthode donnée d'invocation de méthode d'expression, car une variable arity est traité comme un fixe arity dans la première phase. Par exemple, déclaration de m (...) dans une classe qui a déjà déclare m(Objet) causes m(Objet) de ne plus être choisi pour certains invocation des expressions (tels que m(null)), m(Object[]) est plus spécifique.

La deuxième phase (§15.12.2.3) effectue la résolution de surcharge, tout en permettant boxing et unboxing, mais encore s'oppose à l'utilisation de la variable d'arité de l'invocation de méthode. Si non applicable méthode est trouvé au cours de cette phase, puis de continuer le traitement à la troisième phase.

Ceci garantit qu'une méthode n'est jamais choisi par la variable d'arité de l'invocation de méthode, si elle est applicable par fixe arité de l'invocation de méthode.

La troisième phase (§15.12.2.4) permet de surcharger être combinée avec une variable d'arité de méthodes, de boxe, et unboxing.

13voto

scottb Points 1766

Des conseils solides de Joshua Bloch (en vigueur à Java, 2nd Ed):

"que choisir comme arguments pour une méthode surchargée ceux qui ont radicalement différents types."

Un objet avec un de radicalement différent type est celui qui ne peut pas raisonnablement être jeté dans l'autre des types d'arguments. En suivant cette règle peut vous faire épargner des heures de débogage d'un mystérieux erreur peut se produire lorsque le compilateur choisit au moment de la compilation de la surcharge de la méthode que vous ne vous attendiez pas.

Vos lignes de code ne respectent pas cette règle et ouvrir la porte pour les bugs:

public TestOverload(int i){System.out.println("Int");}
public TestOverload(char... c){System.out.println("char");}

Un char est interconvertibles avec un int et donc la seule façon que vous pouvez prédire ce qui va arriver avec les invocations, c'est aller à la Java le Langage de Spécification et de lire un peu les arcanes des règles sur la façon dont les surcharges sont résolus.

Heureusement, cette situation ne devrait pas besoin de JLS de la recherche. Si vous avez des arguments qui ne sont pas radicalement différents les uns des autres, probablement la meilleure option est de ne pas surcharger. Donner les méthodes des noms différents, de sorte qu'il n'y a aucune possibilité d'erreur ou de confusion de la part de tous ceux qui peuvent avoir besoin de maintenir le code.

Le temps est de l'argent.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X