433 votes

La méthode a le même effacement qu'une autre méthode dans le type

Pourquoi est-il légal d'avoir ces deux méthodes dans la même classe?

class Test{
   void add(Set<Integer> ii){}
   void add(Set<String> ss){}
}

J'obtiens l'erreur de compilation "Méthode ajouter(Set) a le même effacement ajouter(Set) une autre méthode de Test de type". alors que je peux le contourner, je me demandais pourquoi javac n'aime pas cela.

Je peux voir que dans de nombreux cas, la logique de ces deux méthodes est très similaire et pourraient être remplacés par un seul

public void add(Set<?> set){}

La méthode, mais ce n'est pas toujours le cas.

C'est très ennuyeux si vous voulez avoir deux constructeurs qui prend ces arguments, car alors vous ne pouvez pas modifier le nom de l'un des constructeurs.

396voto

erickson Points 127945

Cette limitation est une partie de la syntaxe de la langue, pas le Java runtime lui-même. Essentiellement, cette règle vise à éviter les conflits d'héritage de code qui utilise toujours cru types.

Un compilateur comme javac refusent ce type de surcharge, mais si vous créez une classe par d'autres moyens (la rédaction de votre propre compilateur, ou à l'aide d'un byte-code de l'ingénierie de la bibliothèque comme ASM) avec des signatures qui ne diffèrent que par le type de paramètres, l' javac compilateur va résoudre les appels à la méthode correcte de votre classe.

Voici une illustration de pourquoi cela n'a pas été autorisé, établi à partir de la JLS. Supposons que, avant de génériques ont été introduites pour Java, j'ai écrit un code comme ceci:

class CollectionConverter {
  List toList(Collection c) {...}
}

Vous étendre ma classe, comme ceci:

class Overrider extends CollectionConverter{
  List toList(Collection c) {...}
}

Après l'introduction de génériques, j'ai décidé de mettre à jour ma bibliothèque.

class CollectionConverter {
  <T> List<T> toList(Collection<T> c) {...}
}

Vous n'êtes pas prêt à faire toutes les mises à jour, de sorte que vous laissez votre Overrider classe seul. Afin de remplacer l' toList() méthode, la langue de créateurs ont décidé qu'une crue de type a "remplacer l'équivalent de" à tout generified type. Cela signifie que, bien que votre signature de la méthode n'est plus formellement égal à mon super-classe " signature, votre méthode encore des remplacements.

Maintenant, le temps passe et que vous décidez que vous êtes prêt à mettre à jour votre classe. Mais tu vis un peu, et au lieu de modifier l'existant, raw toList() méthode, vous ajoutez une nouvelle méthode comme ceci:

class Overrider extends CollectionConverter {
  @Override
  List toList(Collection c) {...}
  @Override
  <T> List<T> toList(Collection<T> c) {...}
}

En raison de la substitution de l'équivalence de raw types, les deux méthodes sont dans une forme valide pour remplacer l' toList(Collection<T>) méthode. Mais bien sûr, le compilateur a besoin de résoudre une seule méthode. Pour éliminer cette ambiguïté, les classes ne sont pas autorisés à avoir plusieurs méthodes qui sont override-équivalent—qui est, plusieurs méthodes avec les mêmes types de paramètres après l'effacement.

La clé, c'est que c'est une langue de la règle conçu pour permettre la poursuite de l'utilisation de matières premières, pas une limitation résultant de l'effacement des paramètres de type.

Si vous éliminez l'héritage de code (par exemple, en utilisant votre propre, non-strictement-langage Java), ce type de surcharge fonctionne parfaitement. Parce que la méthode de résolution se produit au moment de la compilation, avant l'effacement, le type de la réification n'est pas nécessaire pour faire ce travail.

134voto

GaryF Points 11921

Java utilise de produits génériques de type effacement. Le bit dans les chevrons ( et ) est supprimé, donc vous vous retrouveriez avec deux méthodes qui ont une signature identique (le `` vous voyez l’erreur). Qui n’est pas autorisé car le runtime ne sais pas lequel utiliser pour chaque cas.

Si Java obtient jamais génériques réifiées, alors vous pourriez faire cela, mais c’est sans doute peu probable maintenant.

51voto

bruno conde Points 28120

C'est parce que Java Génériques sont mis en œuvre avec le Type d'Effacement.

Vos méthodes sont traduits, au moment de la compilation, à quelque chose comme:

Méthode de résolution se produit au moment de la compilation et ne tient pas compte des paramètres de type. (voir erickson réponse)

void add(Set ii);
void add(Set ss);

Les deux méthodes ont la même signature sans les paramètres de type, d'où l'erreur.

28voto

kgiannakakis Points 62727

Le problème est que et sont vraiment traité comme un de la JVM. Sélection d’un type pour l’ensemble (chaîne ou entier dans votre cas) est le seul sucre syntaxique utilisée par le compilateur. La JVM ne peut pas faire la distinction entre et `` .

3voto

rossoft Points 1544

Il pourrait être possible que le compilateur traduit Set(Integer) à Set(Object) en byte-code java. Si c’est le cas, Set(Integer) servirait seulement à la phase de compilation pour la vérification de syntaxe.

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