Java-генерики дженериков

У меня есть общий класс, который представляет фрагмент текста. Этот фрагмент текста может иметь любой из нескольких различных режимов (различные типы выделения). Эти режимы представлены Enum. Enum может отличаться для каждого проекта, но он должен реализовать интерфейс, который обеспечивает метод для объединения двух из них (может быть выделен и выделен полужирным). Итак, у меня есть интерфейс:

public interface TextFragmentMode<E extends Enum<E>> {
    /**
     * Will combine the supplied mode with the current mode and return the
     * result.
     * 
     * @param mode The mode to combine with.
     * @return The combined mode.
     */
    public E combine( E mode );
}

Затем мой TextFragment является контейнером как для строки текста, так и для режима. Но когда я пытаюсь объявить класс:

public class TextFragment<E extends TextFragmentMode<E extends Enum<E>>> {
    StringBuilder text;
    E mode;
    ...

Я получаю следующую ошибку:

Синтаксическая ошибка в токене "extends", ожидается

Что, в соответствии с подсветкой синтаксиса eclipse, относится к

E extends Enum<E>

часть кода. Кто-нибудь знает, что я делаю неправильно? Мне нужно что-то пропустить о Generics...

--------------------- edit -------------------

Наконец-то я нашел время, чтобы прочитать "Эффективную Java" Джоша Блоха (второе издание), и выясняется, что он использует этот прецедент в качестве пункта 34: "Эмулировать расширяемые перечисления с интерфейсами". Столько, сколько я хотел бы сказать, что великий ум думает одинаково... Это было бы ПУТЕМ слишком преувеличенным!

Ответ 1

TextFragment<E> нужно сказать две вещи о E.

  • Он "расширяет" TextFragmentMode<E>.
  • Чтобы сделать это, вы также должны ограничить его расширением Enum<E>.

Из-за неуверенности наследования Java вам нужно написать, что наоборот:

public class TextFragment<E extends Enum<E> & TextFragmentMode<E>> {

Ответ 2

Проблема в том, что вы пытаетесь сделать расширения E TextFragmentMode и Enum, которые не являются родственными типами. Какой тип E удовлетворял бы обеим ограничениям?

Я подозреваю, что вы хотите два типа параметров, что-то вроде этого:

public class TextFragment<E extends Enum<E>, M extends TextFragmentMode<E>>

Теперь у вас есть каждое ограничение, выраженное на другом параметре типа, и они оба имеют смысл - вы можете определенно найти E, который является перечислением, и M, который является TextFragmentMode<E>. Однако это довольно сложно...

... вам определенно нужно, чтобы это было общим? Что вы будете делать с M в классе? Не могли бы вы просто взять TextFragmentMode<E> в качестве параметра конструктора (или что-то еще) и снова создать его в одном параметре типа?

Ответ 3

Вам нужно ввести новый тип, который учитывает ограничение Enum

public class TextFragment<T extends Enum<T>, E extends TextFragmentMode<T>> {

Ответ 4

Без тестирования я бы предположил:

public class TextFragment<E extends TextFragmentMode<E>> {

Хмм, короткий тест показывает, что он, похоже, не работает...