2009-11-24 11 views
3

Pour la vie de moi, je ne comprends pas pourquoi le compilateur ne me laisse pas faire ce qui suit ...Pourquoi cette utilisation de Java Generics n'est-elle pas compilée?

import java.util.HashMap; 
import java.util.Map; 

public class TestMap { 
    private final Map<Integer, ? extends Number> map = new HashMap<Integer, Number>(); 

    public void put(Integer key, Long item) { 
     this.map.put(key, item); 
    } 
} 

Pourquoi ligne this.map.put(key, item) provoquer une erreur de compilation? Je sais que je peux changer la déclaration de carte pour utiliser Number plutôt que ? extends Number pour que cela fonctionne mais il me semble que ce que je fais est parfaitement légal, et je préférerais ne pas autoriser les objets Nombre dans la carte . J'utilise Java 1.6.0_13.

+2

Contrairement à ce que vous pensez, '? extends Number' autorisera les objets Number. Le '? étend le caractère générique borné X "X ou une sous-classe de X". – Pesto

+0

Incidemment, 'Number' est un' 'même si l'insertion dans une liste générique était possible, elle n'atteindrait pas ce que vous voulez. Le fait que 'Number' soit abstrait volonté. –

+0

Vous pouvez faire ((Map ) carte) .put (clé, élément); si vous êtes sûr du type. –

Répondre

10

You can't insert into collections that use wildcard types. En effet, alors qu'un List<Float> peut être passé à une méthode qui accepte List<? extends Number>, il est sûr d'insérer une Long en elle. Dans votre cas, on pourrait s'attendre à ce que le compilateur connaisse mieux la définition de la collection, mais ce n'est pas le cas.

+0

Expliqué ici: http://java.sun.com/docs/books/tutorial/extra/generics/wildcards.html – Pesto

+1

Le compilateur ne peut pas l'autoriser car il ne peut pas assumer la responsabilité de l'endroit où cette carte finit par être passée ou utilisé. Bien sûr, en tant qu'être humain, nous pouvons observer le programme et dire qu'il n'est pas utilisé de quelque manière que ce soit, mais le compilateur ne peut regarder que la déclaration «put» contre le type. – Yishai

+2

Vous pouvez insérer dans des collections qui utilisent des types génériques. Vous devez juste le faire correctement. La règle PECS: Producer étend Consumer Super, ce qui signifie que si vous obtenez de la collection, utilisez , si vous y insérez des objets, utilisez . Si vous avez List , vous pouvez insérer un long dans celui-ci. Il vous permet la flexibilité de passer dans la liste ou Liste , etc. –

7

Ceci est lié à covariance des génériques.

Lorsque vous déclarez,

Map<Integer, ? extends Number> map 

vous ne pouvez pas insérer quoi que ce soit à la carte parce que vous ne pouvez pas garantir que ? extends Number est un Long, par exemple.

Imaginez cette situation:

Map<Integer, ? extends Number> map = new HashMap<Integer, Integer>(); 

    public void put(Integer key, Long item) { 
     this.map.put(key, item); 
    } 

Ici, Integer != Long et pourtant à la fois obéissez ? extends Number.

0

Fournir le caractère générique à un type générique le rend effectivement en lecture seule.