Cela signifie que l'argument de type de l'enum doit dériver d'un enum qui a lui-même le même argument de type. Comment cela peut-il se produire ? En faisant de l'argument de type le nouveau type lui-même. Donc, si j'ai un enum appelé StatusCode, ce serait équivalent à :
public class StatusCode extends Enum<StatusCode>
Maintenant, si vous vérifiez les contraintes, nous avons Enum<StatusCode>
- donc E=StatusCode
. Vérifions : est-ce que E
étendre Enum<StatusCode>
? Oui ! Nous allons bien.
Vous vous demandez peut-être quel est l'intérêt de tout ceci :) Eh bien, cela signifie que l'API pour Enum peut se référer à elle-même - par exemple, être capable de dire que Enum<E>
met en œuvre Comparable<E>
. La classe de base est capable de faire les comparaisons (dans le cas des enums) mais elle peut s'assurer qu'elle ne compare que le bon type d'enums entre eux. (EDIT : Enfin, presque - voir l'édition en bas de page).
J'ai utilisé quelque chose de similaire dans mon portage C# de ProtocolBuffers. Il y a des "messages" (immuables) et des "constructeurs" (mutables, utilisés pour construire un message) - et ils sont présentés sous forme de paires de types. Les interfaces concernées sont :
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>
Cela signifie qu'à partir d'un message, vous pouvez obtenir un constructeur approprié (par exemple, pour prendre une copie d'un message et en modifier certains éléments) et à partir d'un constructeur, vous pouvez obtenir un message approprié lorsque vous avez fini de le construire. C'est une bonne chose que les utilisateurs de l'API n'aient pas besoin de s'en préoccuper - c'est horriblement compliqué et il a fallu plusieurs itérations pour en arriver là.
EDIT : Notez que cela ne vous empêche pas de créer des types bizarres qui utilisent un argument de type qui est lui-même correct, mais qui n'est pas le même type. Le but est de donner des avantages dans le droite plutôt que de vous protéger de la mauvais cas.
Donc si Enum
ne sont pas traités "spécialement" en Java de toute façon, vous pourriez (comme indiqué dans les commentaires) créer les types suivants :
public class First extends Enum<First> {}
public class Second extends Enum<First> {}
Second
mettrait en œuvre Comparable<First>
plutôt que Comparable<Second>
... mais First
lui-même serait bien.
10 votes
Voici l'explication que je préfère : Enum groking (aka Enum<E extends Enum<E>>)
0 votes
Cette question a de meilleures réponses : stackoverflow.com/a/3068001/2413303
1 votes
Jeter un coup d'œil à sitepoint.com/self-types-with-javas-generics