Java дженерики дженериков - PullRequest
       5

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

10 голосов
/ 22 ноября 2010

У меня есть универсальный класс, который представляет фрагмент текста.Этот фрагмент текста может иметь любой из нескольких различных режимов (различные типы выделения).Эти режимы представлены 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;
    ...

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

Синтаксическая ошибка на токене «расширяется», ожидаемая

Что, согласно подсветке синтаксиса затмения, относится к части кода

E extends Enum<E>

.Кто-нибудь знает, что я делаю не так?Должно быть, я что-то упускаю из Обобщения ...

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

Наконец-то я нашел время, чтобы прочитать «Эффективную Java» Джоша Блоха (второе издание), и оказалось, что он рассматривает этот вариант использования как Item 34: Emulateрасширяемые перечисления с интерфейсами .Столько, сколько я хотел бы сказать, великий разум думает одинаково ... Это было бы СЛИШКОМ самонадеянным!

Ответы [ 4 ]

12 голосов
/ 22 ноября 2010

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

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

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

public class TextFragment<E extends Enum<E> & TextFragmentMode<E>> {
6 голосов
/ 22 ноября 2010

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

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

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

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

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

1 голос
/ 22 ноября 2010

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

public class TextFragment<T extends Enum<T>, E extends TextFragmentMode<T>> {
0 голосов
/ 22 ноября 2010

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...