2010-10-19 3 views
2

Je fais référence au paradigme de l'article 34 dans Effective Java de Joshua Bloch.   Je voudrais prendre la méthode qu'il utilise pour que chaque enum associé implémente une interface de base, et initialise un EnumMap à partir des "sous-enums". Voir la section du code ci-dessous.   Je reçois une erreur de syntaxe que je ne comprends pas.   Je ne suis pas mis sur cette méthode de mise en œuvre, mais je voudrais comprendre pourquoi cela ne fonctionnera pas.Existe-t-il un moyen de stocker des «enonces extensibles» dans un EnumMap?

Notez que cet exemple suppose que chaque définition de classe se trouve dans son propre fichier.

public interface BaseEnum { 
    ... 
} 

public enum EnumOps1 implements BaseEnum { 
    ... 
} 

public class Widget { 
    public Widget() { 
     regMap = new EnumMap<EnumOps1, WidgetData>(EnumOps1.class); 

     for (EnumOps1 op : EnumOps1.values()) { 
      regMap.put(op, getWidgetData(op.key())); // line with syntax error 
     } 
    } 

    protected Map<? extends BaseEnum, WidgetData> regMap; 
} 

Syntaxe détail d'erreur:

method put in interface java.util.Map <K,V> cannot be applied to given types
required: capture#1 of ? extends BaseEnum, WidgetData
found: EnumOps1, WidgetData

Répondre

4

C'est un problème avec votre wildcarding. Vous devez déclarer votre carte comme Map<BaseEnum, WidgetData> et aussi votre EnumMap comme ex. Il y a beaucoup de discussion sur pourquoi cela est vrai sur SO, mais voir What is PECS (Producer Extends Consumer Super)? par exemple.

Modifier

Malheureusement, vous avez raison - vous ne pouvez pas utiliser un EnumMap là. C'est parce que vous essayez d'utiliser une interface, et EnumMap stipule (comme il faut un type T extends Enum<T>) qu'il doit être un Enum seulement.

Vos choix se résument essentiellement à

1) Utilisez un EnumMap<EnumOps1,...> et perdre sur le polymorphisme

2) Utilisez un HashMap<BaseEnum,...> et tout fonctionne très bien, mais vous devez utiliser une carte non-Enum.

3) Utilisez des caractères génériques pendant que vous essayez, mais vous rencontrerez les restrictions PECS que j'ai liées précédemment, par exemple. vous pouvez ajouter ou supprimer des éléments mais pas les deux (super vs extends)

+0

Lorsque je tente cette déclaration et instanciation, je reçois une autre erreur de syntaxe: paramètre de type BaseEnum pas dans sa limite. Cette erreur est sur la ligne d'instanciation (regMap = ...) Des idées? – stever

+0

Je suis d'accord avec l'exactitude de votre réponse. Cependant, il n'est pas tout à fait clair pourquoi cette ligne particulière jette l'erreur. Dans tous les cas où l'EnumMap est instanciée ou appelée, une énumération lui est transmise. Je m'excuse si je manque quelque chose d'évident. – stever

+0

Désolé, postez le code exact que vous essayez maintenant? –

1

Voici quelque chose que j'ai fait après des heures de recherche et de tentatives. Je voulais profiter des avantages d'EnumMap et ne pas être limité à une seule classe enum, mais plutôt à plusieurs autres qui implémentaient la même interface. Dans l'exemple ci-dessous, j'avais une interface nommée Layout que j'avais quelques classes enum l'étendant. J'ai ensuite créé une classe auxiliaire, Record, qui utilisait EnumMap pour gérer et stocker des valeurs String dans les énumérations de ma classe enum et j'en avais besoin pour accepter différentes classes enum qui étendaient toutes l'interface Layout. Donc, j'ai créé la classe suivante (le raccourci ci-dessous pour donner une idée):

enter code here 
public class Record<T extends Enum<T> & Layout> 
{ 
    private Map<T, String> fields; 

    /**Constructor accepting the class name of one of the enums implementing layout 
    */ 
    public Record(Class<T> layout_type) 
    { 
     fields = new EnumMap<T, String>(layout_type); 
     for (T type : layout_type.getEnumConstants()) 
     { 
      fields.put(type, ""); 
     } 
    } 

    /*Here's an example of a method that manipulates (adds or replaces) an enum map 
    *item and its corresponding String value in the enum map 
    *This won't warn any unchecked exceptions or anything and I can pass any 
    *enum from my enum class that implements layout enum.NAME 
    */ 
    public void setRecordFieldValue(final T item, String value) 
    { 
     fields.put(item, value); 
    } 
} 

Questions connexes