Это означает, что аргумент типа для enum должен происходить от enum, который сам имеет такой же аргумент типа. Как это может случиться? Делая аргумент типа новым типом. Так что если бы у меня был enum с именем StatusCode, он был бы эквивалентен:
public class StatusCode extends Enum<StatusCode>
Теперь, если вы проверите ограничения, у нас есть Enum<StatusCode>
- так что E=StatusCode
. Давайте проверим: E
распространяется Enum<StatusCode>
? Да! Мы в порядке.
Вы вполне можете спросить себя, в чем смысл этого :) Ну, это означает, что API для Enum может ссылаться на себя - например, быть в состоянии сказать, что Enum<E>
реализует Comparable<E>
. Базовый класс может выполнять сравнения (в случае перечислений), но он может убедиться, что он сравнивает только правильные типы перечислений друг с другом. (РЕДАКТИРОВАТЬ: Ну, почти - см. Редактирование внизу.)
Я использовал нечто подобное в моем C # -порте ProtocolBuffers. Существуют «сообщения» (неизменяемые) и «строители» (изменяемые, используемые для создания сообщения) - и они представляют собой пары типов. Используемые интерфейсы:
public interface IBuilder<TMessage, TBuilder>
where TMessage : IMessage<TMessage, TBuilder>
where TBuilder : IBuilder<TMessage, TBuilder>
public interface IMessage<TMessage, TBuilder>
where TMessage : IMessage<TMessage, TBuilder>
where TBuilder : IBuilder<TMessage, TBuilder>
Это означает, что из сообщения вы можете получить соответствующего компоновщика (например, взять копию сообщения и изменить некоторые биты), а из компоновщика вы можете получить соответствующее сообщение, когда закончите его сборку. Это хорошая работа, и пользователям API не нужно на самом деле заботиться об этом - это ужасно сложно, и потребовалось несколько итераций, чтобы добраться туда, где он есть.
РЕДАКТИРОВАТЬ: обратите внимание, что это не мешает вам создавать нечетные типы, которые используют аргумент типа, который сам по себе, но не тот же тип. Цель состоит в том, чтобы предоставить преимущества в правильном деле, а не защитить вас от неправильного дела.
Таким образом, если бы Enum
не обрабатывалось «специально» в Java, вы могли бы (как отмечено в комментариях) создать следующие типы:
public class First extends Enum<First> {}
public class Second extends Enum<First> {}
Second
будет реализовывать Comparable<First>
вместо Comparable<Second>
... но сам First
будет в порядке.