Это означает, что аргумент типа для 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
само по себе было бы хорошо.