395 votes

Quelles sont les raisons pourquoi Map.get (Object key) n’est pas (entièrement) générique

Quelles sont les raisons derrière la décision de ne pas avoir un générique entièrement get méthode dans l’interface de `` .

Pour clarifier la question, est la signature de la méthode

``

Au lieu de

``

et je me demande pourquoi (même chose pour `` ).

258voto

newacct Points 42530

Comme mentionné par d'autres, la raison pour laquelle get(), etc. n'est pas générique, car la clé de l'entrée de la récupération n'a pas à être le même type que l'objet que vous passez en get(); la spécification de la méthode ne nécessite qu'ils soient égaux. Cela découle de la façon dont l' equals() méthode prend un Objet en paramètre, pas seulement le même type que l'objet.

Bien qu'il puisse être vrai que de nombreuses classes ont equals() défini de telle sorte que ses objets ne peuvent être égaux aux objets de sa propre classe, il ya beaucoup d'endroits en Java si ce n'est pas le cas. Par exemple, la spécification d' List.equals() affirme que les deux objets de la Liste sont égales si elles sont à la fois des Listes et ont le même contenu, même si elles sont différentes implémentations de l' List. Afin de revenir à l'exemple de cette question, conformément à la spécification de la méthode est possible d'avoir un Map<ArrayList, Something> et pour moi d'appeler get() avec un LinkedList comme argument, et il doit récupérer la clé qui est une liste avec le même contenu. Ce ne serait pas possible si get() sont génériques et restreint son type d'argument.

105voto

Jon Skeet Points 692016

Un super codeur Java chez Google, Kevin Bourrillion, a écrit au sujet de exactement cette question dans un billet de blog il y a un moment (il est vrai que dans le contexte de l' Set au lieu de Map). Les plus pertinents de la phrase:

Uniformément, les méthodes de Java Les Collections de Cadre (et Google Les Collections de la Bibliothèque de trop) jamais restreindre les types de leurs paramètres sauf quand c'est nécessaire pour éviter la collection à partir de l'obtention cassé.

Je ne suis pas entièrement sûr je suis d'accord avec elle comme un principe .NET semble être bien exigeant le droit type de clé, par exemple - mais ça vaut la peine de suivre le raisonnement dans le billet de blog. (Avoir mentionné .NET, il vaut la peine d'expliquer qu'une partie de la raison pour laquelle il n'est pas un problème .NET est qu'il y a le plus grand problème .NETTE de la plus limitée des écarts...)

29voto

Brian Agnew Points 143181

Le contrat est exprimé ainsi:

Plus formellement, si cette carte contient un la cartographie à partir d'une clé k pour une valeur de v tel que (key==null ? k==null : clé.est égal à(k)), alors cette méthode retourne v; sinon, elle renvoie null. (Il peut y avoir au plus un de ces la cartographie.)

(mon emphase)

et en tant que tel, la réussite d'une clé de recherche repose sur la touche input de la mise en œuvre de l'égalité de la méthode. Ce n'est pas nécessairement dépendante de la classe de k.

17voto

erickson Points 127945

C'est une application de Postel, de la Loi, "être prudent dans ce que vous faites, être libéral dans ce que vous acceptez des autres."

L'égalité des contrôles peuvent être réalisés indépendamment de leur type; l' equals méthode est définie sur l' Object de la classe et accepte n'importe quel Object en tant que paramètre. Ainsi, il est logique pour les principaux équivalence, et les opérations de base sur les principaux équivalence, à accepter tout Object type.

Lorsqu'une carte renvoie des valeurs de clé, il conserve autant de type d'informations qu'il peut, en utilisant le paramètre de type.

12voto

Yardena Points 1640

Je pense que cette section de Génériques Tutoriel vous explique la situation (je souligne):

"Vous avez besoin pour faire certain que l'API générique n'est pas trop restrictive; il doit continuer à soutenir le contrat original de l'API. Considérons à nouveau quelques exemples à partir de java.util.Collection. Le pré-générique de l'API ressemble:

interface Collection { 
  public boolean containsAll(Collection c);
  ...
}

Une naïve tentative de generify c'est:

interface Collection<E> { 
  public boolean containsAll(Collection<E> c);
  ...
}

Tout cela est certainement le type de sécurité, il n'est pas à la hauteur de l'API du contrat initial. Le containsAll() la méthode fonctionne avec n'importe quel type de l'arrivée de la collection. Il ne réussir si la future collection vraiment ne contient que des instances de E, mais:

  • Le type statique de l'entrants collection peut être différente, peut-être parce que l'appelant ne connaît pas le précise le type de la collection en cours passé, ou peut-être parce que c'est un Collection<S>,où S est un sous-type d'E.
  • Il est parfaitement légitime d'appeler containsAll() avec une collection d'un type différent. L' routine de travail, retour faux."

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