Использование EnumSet перечисления, реализующего интерфейс

у меня есть интерфейс

public interface TerminalSymbol {
    // methods ...
}

перечисление

// common usage enum that I need
public enum Common implements TerminalSymbol {
    EPSILON;

    @Override
    // methods ...
}

и я хотел бы сделать что-то вроде:

enum Term implements TerminalSymbol {
    A, B, C, ...

    @Override
    // methods ...
}

EnumSet<? extends TerminalSymbol> terminalSymbols = EnumSet.allOf(Term.class);
terminalSymbol.add(Common.EPSILON); // this line gives me error

и эта ошибка (в моем случае):

The method add(capture#1-of ? extends TerminalSymbol) in the type AbstractCollection<capture#1-of ? extends TerminalSymbol> is not applicable for the arguments (Common)

теперь я знаю, что если бы я использовал Set<SomeInterface>, я мог бы предотвратить этот тип ошибки (и я мог бы продолжить разработку моего класса, представляющего формальную грамматику), но я хотел бы использовать EnumSet, потому что он, вероятно, будет более эффективным, чем HashSet. Как я могу решить эту проблему?


person Mega-X    schedule 16.05.2013    source источник
comment
Действительно ли критично с точки зрения эффективности то, что вы пытаетесь использовать EnumSet вместо HashSet, или это просто ради использования EnumSet? С точки зрения дженериков, в конечном итоге вы пытаетесь создать некоторое загрязнение кучи, потому что вы создали Set из Terms, но пытаетесь добавить в него экземпляр Common.   -  person Bhesh Gurung    schedule 16.05.2013
comment
Да, теперь я понимаю, что если бы я хотел сделать add(), мне нужно было добавить символ EPSILON в перечисление терминальных символов, но мне нужен был этот символ epsilon в общем перечислении, поэтому я должен использовать решение HashSet: D   -  person Mega-X    schedule 16.05.2013


Ответы (3)


EnumSet эффективен благодаря ключевому ограничению, заключающемуся в том, что он содержит только элементы одного перечисления. Это достигается за счет эффективного сохранения своего состояния с опорой на ordinal число каждого члена перечисления, в основном ведущего себя как BitSet. Так что, к сожалению, вы не сможете воспользоваться его преимуществами, если вам нужно несколько перечислений.

Ближе всего к этой цели вы можете подойти, разработав собственную схему нумерации, которая отличается для всех ваших перечислений, и используя BitSet для их эффективного хранения.

person Marko Topolnik    schedule 16.05.2013

EnumSet может содержать элементы только одного перечисляемого класса.

Из документации по Java API:

Все элементы в наборе перечислений должны исходить из одного типа перечисления, который указывается явно или неявно при создании набора.

Как вы заметили, альтернативой является использование Set<TerminalSymbol>.

person Andy Thomas    schedule 16.05.2013

EnumSet — это специальная реализация интерфейса Set только для enums. Один экземпляр EnumSet может работать с конкретным перечислением только потому, что его реализация основана на ordinal перечисления.

Вы создали EnumSet для Term и пытаетесь добавить туда элемент перечисления Common. Это очевидно невозможно. Вы должны либо создать EnumSet для Common, либо, если вы хотите хранить элементы обоих перечислений, используйте другую реализацию Set, например. HashSet.

person AlexR    schedule 16.05.2013