Oznacza to, że argument typu dla wyliczenia musi pochodzić z wyliczenia, które samo ma ten sam argument typu. Jak to się stało? Poprzez uczynienie argumentu type nowym typem. Więc jeśli mam wyliczenie o nazwie StatusCode, byłoby to równoważne z:
public class StatusCode extends Enum<StatusCode>
Teraz, jeśli sprawdzisz ograniczenia, mamy Enum<StatusCode>
- więc E=StatusCode
. Sprawdźmy: E
rozszerza sięEnum<StatusCode>
? Tak! W porządku.
Możesz zadawać sobie pytanie, o co w tym wszystkim chodzi :) Cóż, oznacza to, że API dla Enum może odnosić się do siebie - na przykład, będąc w stanie powiedzieć, że Enum<E>
implementuje Comparable<E>
. Klasa bazowa jest w stanie dokonywać porównań (w przypadku wyliczeń), ale może upewnić się, że porównuje ze sobą tylko właściwy rodzaj wyliczeń. (EDYCJA: Cóż, prawie - zobacz edycję na dole.)
Użyłem czegoś podobnego w moim porcie C # ProtocolBuffers. Istnieją „wiadomości” (niezmienne) i „konstruktorzy” (zmienne, używane do tworzenia wiadomości) - i występują jako pary typów. Stosowane interfejsy to:
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>
Oznacza to, że z wiadomości możesz uzyskać odpowiedni konstruktor (np. Aby skopiować wiadomość i zmienić kilka bitów), a od konstruktora możesz otrzymać odpowiednią wiadomość, gdy skończysz ją budować. To dobra robota, ale użytkownicy API nie muszą się tym przejmować - jest to horrendalnie skomplikowane i wymagało kilku iteracji, aby dostać się tam, gdzie jest.
EDYCJA: Zauważ, że nie powstrzymuje cię to przed tworzeniem dziwnych typów, które używają argumentu typu, który sam w sobie jest w porządku, ale nie jest tego samego typu. Celem jest raczej zapewnienie korzyści we właściwym przypadku niż ochrona przed złem przypadkiem.
Więc jeśli i Enum
tak nie były obsługiwane „specjalnie” w Javie, można (jak zauważono w komentarzach) utworzyć następujące typy:
public class First extends Enum<First> {}
public class Second extends Enum<First> {}
Second
wdrożyłby Comparable<First>
raczej niż Comparable<Second>
... ale First
samo byłoby w porządku.