Carte avec plusieurs types de valeur avec des avantages de génériques

Je veux créer une carte qui vous offrent tous les avantages des médicaments génériques, tout en soutenant plusieurs différents types de valeurs. Je considère être les deux principaux avantages de générique collections:

  • moment de la compilation des avertissements sur la mise mauvaises choses dans la collection
  • pas besoin de cast lors de l'obtention des choses hors de collections

Donc, ce que je veux, c'est une carte:

  • qui prend en charge plusieurs objets de valeur,
  • vérifie les valeurs de mettre dans la carte (de préférence au moment de la compilation)
  • sait ce que les valeurs de l'objet sont lors de l'obtention de la carte.

Le cas de base, l'utilisation de génériques, est:

Map<MyKey, Object> map = new HashMap<MyKey, Object>();
//No type checking on put();
map.put(MyKey.A, "A");  
map.put(MyKey.B, 10);
//Need to cast from get();
Object a = map.get(MyKey.A); 
String aStr = (String) map.get(MyKey.A);

J'ai trouvé un moyen de résoudre le deuxième problème, par la création d'un AbstractKey, qui est generified par la classe de valeurs associées à cette clé:

public interface AbstractKey<K> {
}
public enum StringKey implements AbstractKey<String>{
  A,B;  
}
public enum IntegerKey implements AbstractKey<Integer>{
  C,D;
}

Je peux alors créer un TypedMap, et remplacer le put() et get() méthodes:

public class TypedMap extends HashMap<AbstractKey, Object> {
  public <K> K put(AbstractKey<K> key, K value) {
    return (K) super.put(key, value);
  }
  public <K> K get(AbstractKey<K> key){
    return (K) super.get(key);
  }
}

Cela permet à l'suivantes:

TypedMap map = new TypedMap();
map.put(StringKey.A, "A");
String a = map.get(StringKey.A);

Cependant, je n'ai pas toutes les erreurs de compilation si je l'ai mis dans la mauvaise valeur pour la clé. Au lieu de cela, je reçois un runtime ClassCastException sur get().

map.put(StringKey.A, 10); //why doesn't this cause a compile error?
String a = map.get(StringKey.A); //throws a ClassCastException

L'idéal serait si ce .put() pourrait donner une erreur de compilation.
En tant que meilleur deuxième, je peux obtenir l'exécution ClassCastException d'être jeté dans le mis() la méthode.

//adding this method to the AbstractKey interface:
public Class getValueClass();

//for example, in the StringKey enum implementation:
public Class getValueClass(){
  return String.class;
}

//and override the put() method in TypedMap:
public <K> K put(AbstractKey<K> key, K value){
  Object v = key.getValueClass().cast(value);
  return (K) super.put(key, v);
}

Maintenant, le ClassCastException est levée lors de la mettre dans la carte, comme suit. C'est préférable, car elle permet de plus facile/rapide de débogage pour identifier d'où une mauvaise clé/valeur de la combinaison a été mis dans le TypedMap.

map.put(StringKey.A, 10); //now throws a ClassCastException

Donc, j'aimerais savoir:

  • Pourquoi ne pas map.put(StringKey.A, 10) provoquer une erreur de compilation?
  • Comment pourrais-je adapter cette conception pour obtenir des erreurs de compilation, mis de, là où la valeur n'est pas associé au type générique de la clé?

  • Est que c'est une conception adaptée pour atteindre ce que je veux (voir plus haut)? (Toutes les autres idées/commentaires/avertissements serait également appréciée...)

  • Existe t il d'autres modèles que je pourrais utiliser pour obtenir ce que je veux?

MODIFIER précisions:

  • Si vous pensez que c'est une mauvaise conception - pouvez-vous expliquer pourquoi?
  • J'ai utilisé de la Ficelle et Entier comme exemple de types de valeur - en réalité, j'ai une multitude de Clé /valeur de type paires que je voudrais être en mesure d'utiliser. Je veux utiliser ces dans une seule carte - c'est l'objectif.
Tellement drôle comment j'ai passé tous hier en passant par exactement la même explorations—avec de légères déviations—vous d'élucider ci-dessus

OriginalL'auteur amaidment | 2012-05-03