有没有办法存储“可扩展枚举”?在 EnumMap 中?

发布于 2024-09-28 13:01:27 字数 839 浏览 3 评论 0原文

我指的是 Joshua Bloch 所著的《Effective Java》第 34 条中的范例。我想采用他正在使用的方法,即让每个相关的枚举实现一个基本接口,并从“子枚举”初始化一个枚举映射。请参阅下面的代码部分。  我收到一个我不明白的语法错误。我还没有确定这种实现方法,但我想了解为什么它不起作用。

请注意,此示例假设每个类定义都在其自己的文件中。

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;
} 

语法错误详细信息:

接口 java.util.Map 中放入的方法无法应用于给定类型
必需:捕获#1 的?扩展 BaseEnum、WidgetData
发现:EnumOps1,WidgetData

I'm referring to the paradigm in Item 34 in Effective Java by Joshua Bloch.  I would like to take the method he's using which is to have each related enum implement a base interface, and initialize an EnumMap from the "sub-enums." See the code section below.  I'm getting a syntax error which I don't understand.  I'm not set on this method of implementation, but I would like to understand why it won't work.

Note that this example assumes each class definition is in its own file.

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;
} 

Syntax error detail:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

北笙凉宸 2024-10-05 13:01:27

这是你的通配符的问题。您应该将您的地图声明为 Map 并将您的 EnumMap 声明为 ex。 HashMap

关于为什么这在 SO 上是正确的有很多讨论,但请参阅 什么是 PECS(生产者扩展消费者超级)? 例如。

编辑

遗憾的是,你是对的 - 你不能在那里使用 EnumMap。这是因为您正在尝试使用接口,并且 EnumMap 规定(因为它需要类型 T extends Enum)它必须只是 Enum。

您的选择基本上可以归结为

1) 使用 EnumMap 并失去多态性

2) 使用 HashMap code> 一切正常,但您必须使用非枚举映射。

3)在尝试时使用通配符,但您会遇到我之前链接的 PECS 限制,例如您可以添加或删除元素,但不能同时添加或删除元素(superextends

It's a problem with your wildcarding. You should declare your map as Map<BaseEnum, WidgetData> and also your EnumMap as ex. HashMap<BaseEnum, WidgetData>

There's plenty of discussion of why this is true on SO, but see What is PECS (Producer Extends Consumer Super)? for example.

Edit

Sadly, you're right - you can't use an EnumMap there. This is because you are trying to use an interface, and EnumMap stipulates (as it requires a type T extends Enum<T>) that it must be an Enum only.

Your choices basically boil down to

1) Use an EnumMap<EnumOps1,...> and lose out on the polymorphism

2) Use a HashMap<BaseEnum,...> and everything works fine but you have to use a non-Enum map.

3) Use wildcards as you are trying, but you'll run into the PECS restrictions I linked earlier e.g. you can add or remove elements but not both (super vs extends)

平安喜乐 2024-10-05 13:01:27

这是我经过数小时的研究和尝试后所做的事情。我希望获得 EnumMap 的好处,而不是仅限于一个枚举类,而是许多实现相同接口的不同枚举类。
在下面的示例中,我有一个名为 Layout 的接口,我有一些扩展它的枚举类。然后,我创建了一个辅助类 Record,它利用 EnumMap 来处理和存储将一些 String 值映射到我的枚举类中的枚举,并且我需要它接受所有扩展 Layout 接口的不同枚举类。所以我创建了以下类(为了给出一个想法,下面将其缩短):

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);
    }
}

Here's something I did after hours of research and attempts. I wanted to reap the benefits of EnumMap and not be restricted to just one enum class but rather many different ones that were implementing the same interface.
In the below example, I had an interface named Layout that I had a few enum classes extending it. I then created a helper class, Record, which utilized the EnumMap to handle and store mapping some String values to the enums in my enum class and I needed it to accept different enum classes that were all extending the Layout interface. So I created the following class (its shortened below to give an idea):

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);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文