Есть ли способ хранить "расширяемые перечисления" в EnumMap? - PullRequest
2 голосов
/ 20 октября 2010

Я имею в виду парадигму в пункте 34 «Эффективной Явы» Джошуа Блоха. Я хотел бы взять метод, который он использует, который заключается в том, чтобы каждый связанный enum реализовал базовый интерфейс, и инициализировал EnumMap из "под-перечислений". Смотрите раздел кода ниже. Я получаю синтаксическую ошибку, которую не понимаю. Я не настроен на этот метод реализации, но я хотел бы понять, почему он не будет работать.

Обратите внимание, что в этом примере предполагается, что каждое определение класса находится в своем собственном файле.

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. Карта <K,V> не может быть применена к данным типам
требуется: захват № 1 из? расширяет BaseEnum, WidgetData
найдено: EnumOps1, WidgetData

Ответы [ 2 ]

4 голосов
/ 20 октября 2010

Это проблема с вашим подстановочным знаком. Вы должны объявить свою карту как Map<BaseEnum, WidgetData>, а также EnumMap как ex. HashMap<BaseEnum, WidgetData>

Существует множество дискуссий о том, почему это верно для SO, но посмотрите Что такое PECS (Producer Extends Consumer Super)? , например.

1009 ** * Редактировать 1010 ** * 1011

К сожалению, вы правы - вы не можете использовать EnumMap там. Это потому, что вы пытаетесь использовать интерфейс, и EnumMap оговаривает (поскольку для него требуется тип T extends Enum<T>), что это должен быть только Enum.

Ваш выбор в основном сводится к

1) Используйте EnumMap<EnumOps1,...> и проиграйте в полиморфизме

2) Используйте HashMap<BaseEnum,...> и все работает нормально, но вы должны использовать карту не-Enum.

3) Используйте подстановочные знаки, когда вы пытаетесь, но вы столкнетесь с ограничениями PECS, которые я связывал ранее, например, Вы можете добавлять или удалять элементы, но не оба (super против extends)

1 голос
/ 02 октября 2013

Вот что я сделал после часов исследований и попыток.Я хотел воспользоваться преимуществами EnumMap и не ограничиваться одним классом enum, а множеством разных, которые реализовывали один и тот же интерфейс.В приведенном ниже примере у меня был интерфейс с именем Layout, в котором у меня было несколько классов enum, расширяющих его.Затем я создал вспомогательный класс 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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...