Pourquoi ne pas Java enum littéraux être en mesure d'avoir des paramètres de type générique?
Java enums sont grands. Donc, sont des génériques. Bien sûr, nous connaissons tous les limites de cette dernière en raison de type de l'effacement. Mais il y a une chose que je ne comprends pas, Pourquoi ne puis-je pas créer un enum comme ceci:
public enum MyEnum<T> {
LITERAL1<String>,
LITERAL2<Integer>,
LITERAL3<Object>;
}
Ce paramètre de type générique <T>
pourrait alors être utile dans différents endroits. Imaginez un paramètre de type générique à une méthode:
public <T> T getValue(MyEnum<T> param);
Ou même dans l'énumération de la classe elle-même:
public T convert(Object o);
Exemple plus concret n ° 1
Depuis l'exemple ci-dessus peut sembler trop abstrait pour certains, voici un exemple de pourquoi je veux faire ce. Dans cet exemple, je veux utiliser
- Enums, parce que je peux énumérer un ensemble fini de propriété touches
- Génériques, parce que je peux avoir de la méthode de niveau de type de sécurité pour le stockage des propriétés
public interface MyProperties {
public <T> void put(MyEnum<T> key, T value);
public <T> T get(MyEnum<T> key);
}
Exemple plus concret n ° 2
J'ai une énumération des types de données:
public interface DataType<T> {}
public enum SQLDataType<T> implements DataType<T> {
TINYINT<Byte>,
SMALLINT<Short>,
INT<Integer>,
BIGINT<Long>,
CLOB<String>,
VARCHAR<String>,
...
}
Chaque enum littérale serait évidemment d'avoir des propriétés supplémentaires basés sur le type générique <T>
, alors que dans le même temps, être un enum (immuable, singleton, énumérable, etc. etc.)
Question:
Ne pas penser à cela? Est-ce un compilateur limitation? Compte tenu du fait que le mot-clé "enum" est mis en œuvre en tant que sucre syntaxique, représentant le code généré pour la JVM, je ne comprends pas cette limitation.
Qui peut il m'expliquer? Avant de vous répondre, pensez à ceci:
- Je sais que les types génériques sont effacés 🙂
- Je sais qu'il existe des solutions de contournement en utilisant des objets de la Classe. Ils sont des solutions de contournement.
- Types génériques résultat généré par le compilateur le type de jette, le cas échéant (par exemple, lors de l'appel de la fonction convert() la méthode
- Le générique de type <T> serait sur les enum. Par conséquent, il est lié par chacune des enum littéraux. Donc le compilateur sait, à quel type à appliquer lors de l'écriture de quelque chose comme
String string = LITERAL1.convert(myObject); Integer integer = LITERAL2.convert(myObject);
- La même chose s'applique pour le paramètre de type générique dans le
T getvalue()
méthode. Le compilateur peut appliquer la conversion de type lors de l'appel deString string = someClass.getValue(LITERAL1)
- Je ne comprends pas cette limitation soit. Je suis tombé sur cette récemment où mon enum contenus différents "Comparables" types, et avec les médicaments génériques, la comparaison des types du même genre, peut être comparé sans avertissements qui doivent être supprimés (même si au moment de l'exécution de la bonne, lesquels devraient être comparés). Je pourrais avoir réussi à se débarrasser de ces mises en garde par l'utilisation d'un type lié dans l'enum pour spécifier le type comparable a été pris en charge, mais à la place j'ai dû ajouter de la SuppressWarnings annotation - pas moyen de contourner cela! Depuis compareTo ne jeter une classe cast exception de toute façon, c'est ok, je suppose, mais quand même...
- J'ai voté pour fermer ma propre question comme étant "non constructif". Cette question ne peut être répondu sans commencer à disserter sur le PLAN de décisions au sujet de la langue de conception ou de ma propre intention (par exemple, à l'origine, accepté, mais a supprimé la réponse, pour ceux qui peuvent voir supprimé réponses)...
- (+1) je suis juste au milieu, à essayer de fermer un type de la sécurité de l'écart dans mon projet d'arrêté morts par cette limitation arbitraire. Il suffit de considérer ceci: tournez le
enum
dans un "typesafe enum" l'idiome nous avons utilisé avant de Java 1.5. Tout à coup, vous pouvez avoir votre enum membres paramétrée. C'est probablement ce que je vais faire maintenant. - C'est une chose que vous pouvez faire, mais vous perdrez toutes les awesome enum caractéristiques qui sont cuits dans le langage et la JDK. Par exemple
switch
de soutien, ouEnumSet
etEnumMap
- Je sais, c'est mal 🙂 En fait, j'ai dû abandonner pour l'une des deux énumérations où j'ai voulu l'appliquer.
- J'ai du mal à penser à un scénario qui pourrait être utile. Avez-vous un plus concrète scénario?
- Mise à jour de la question avec un exemple concret à partir de jOOQ, alors qu'il aurait été très utile dans le passé.
- Je vois votre point de maintenant. Ressemble à une cool une nouvelle fonctionnalité. Peut-être devriez vous suggérons projet de pièce de monnaie de la liste de diffusion je vois d'autres propositions intéressantes, là, sur les énumérations, mais pas une comme la vôtre.
- Tout à fait d'accord. Enum sans les génériques sont paralysés. Votre cas #1 est aussi la mienne. Si j'ai besoin d'générique enum j'abandonne JDK5 et le mettre en œuvre de plain old Java 1.4 style. Cette approche a également l'avantage supplémentaire: je ne suis pas obligé d'avoir toutes les constantes dans une catégorie ou d'un même package. Ainsi, le paquet par la fonctionnalité de style est en fait beaucoup mieux. C'est juste parfait pour la configuration comme "enum" - les constantes sont répartis dans les paquets en fonction de leur logique du sens (et si je veux les voir tous, j'ai le type de hiérarchie montré).
- C'est que la liste est encore actif? De toute façon, je n'ai pas fait de super expérience sur ces listes dans le passé...
- En fait, c'est vraiment une bonne question. C'est une honte de voir que pratiquement toutes les réponses sont soit manquants, le point ou le non-respect entièrement le problème. Dans un sens, je suppose que c'est normal, cependant, de voir comme il semble y avoir pas de réponse évidente.
- Une bonne idée, mais il ne fait qu'ajouter de la JLS, faire des travaux d'entretien et de nouvelles fonctionnalités beaucoup plus fort, donc la résistance. Java est déjà piraté en avant et en arrière en arrière des raisons de compatibilité, en gardant pur est je pense un #1 prio maintenant. Donc c'est un argument que, si vous avez besoin de ce niveau de complexité de votre enums, vous devriez peut-être ce modèle avec OO au lieu.
- Qu'entendez-vous par "garder pure". Aussi, comment sont génériques enums a) complexes et b) de ne pas OO? D'ailleurs, avez-vous vérifié openjdk.java.net/jeps/301?
Vous devez vous connecter pour publier un commentaire.
C'est maintenant en cours de discussion comme de JEP-301 Amélioré les Énumérations. L'exemple donné dans la PEC est, ce qui est précisément ce que je cherchais:
Malheureusement, le JEP est toujours aux prises avec d'importants problèmes: http://mail.openjdk.java.net/pipermail/amber-spec-experts/2017-May/000041.html
La réponse est dans la question:
Aucune de ces deux méthodes sont possibles, depuis le type d'argument est effacé.
À réaliser ces méthodes vous pouvez, toutefois, construire votre enum comme:
public T convert(Object);
. Je devine que cette méthode pourrait par exemple se limiter à un tas de différents types de <T>, qui, par exemple, est une Chaîne de caractères. La construction de l'objet String est l'exécution, rien que le compilateur ne. Par conséquent, vous devez connaître le runtime type, tels que String.class. Ou ai-je raté quelque chose?public final static String FOO;
avec un bloc statiquestatic { FOO = "bar"; }
- aussi constantes sont évalués, même lorsqu'il est connu au moment de la compilation.Il existe d'autres méthodes ENUM qui ne fonctionne pas. Ce serait
MyEnum.values()
retour?Ce sujet
MyEnum.valueOf(String name)
?Pour le valueOf si vous pensez que le compilateur pourrait rendre méthode générique comme
afin de l'appeler comme
MyEnum<String> myStringEnum = MyEnum.value("some string property")
, qui ne fonctionne pas non plus.Par exemple si vous appelez
MyEnum<Int> myIntEnum = MyEnum.<Int>value("some string property")
?Il n'est pas possible de mettre en œuvre cette méthode fonctionne correctement, par exemple à jeter l'exception ou retourne null quand vous l'appelez comme
MyEnum.<Int>value("some double property")
en raison du type d'effacement.MyEnum<?>[] values()
etMyEnum<?> valueOf(...)
MyEnum<Int> blabla = valueOf("some double property");
parce que les types ne sont pas compatibles. Vous souhaitez aussi dans ce cas, pour obtenir la valeur null parce que vous voulez retourner MyEnum<Int> qui n'existe pas pour le double nom de la propriété et vous ne pouvez pas faire cette méthode fonctionne correctement en raison de l'effacement.Enum
a beaucoup d'autres fonctionnalités utiles, et celui-ci serait facultatif et est très utile aussi...Parce que vous ne pouvez pas. Sérieusement. Qui peut être ajouté à la langue spec. Il n'a pas été. Il serait ajouter un peu de complexité. Que de rentabilité signifie qu'elle n'est pas une priorité.
Mise à jour: à l'heure actuelle d'être ajoutée à la langue sous JEP 301: l'amélioration des Enums.
Franchement, cela ressemble plus à une solution en quête de problème qu'autre chose.
Le but entier de l'enum de java est de modéliser une énumération des instances d'un type qui partagent des propriétés similaires d'une manière qui assure la cohérence et la richesse au-delà de celle de comparable Entier ou Chaîne de représentations.
Prendre un exemple d'un livre de texte enum. Ce n'est pas très utile ou compatible:
Pourquoi voudrais-je à mes différentes planètes afin d'avoir différents type générique de conversions? Ce problème permet-il de résoudre? Elle justifie compliquer la langue de la sémantique? Si je n'ai besoin de ce comportement est un enum le meilleur outil pour y parvenir?
En outre comment voulez-vous gérer des conversions?
par Exemple
Son assez facile avec
String
Integer
à fournir le nom ou ordinale. Mais les génériques permettant de vous fournir tout type. Comment voulez-vous gérer la conversion deMyComplexClass
? Maintenant, votre déblayage de deux constructions en forçant le compilateur de savoir qu'il existe un sous-ensemble limité de types qui peuvent être fournis à des génériques enums et l'introduction de nouvelles confusion de concept(Génériques) qui semble échapper à beaucoup de programmeurs.StringifierEnum
. Et vous voulez generify ilNUMBER.convert(Number)
,CURRENCY.convert(Double)
,TO_STRING.convert(Object)
,LYRICS.convert(String[])
... Pourquoi devraient-ils tous être forcé de prendreObject
comme un type d'argument? Pourquoi ne pas generify avecStringifierEnum<T>
etpublic abstract String convert ( T object )
? De l'incapacité à utiliser les génériques ici conserve facilement détectable erreurs d'être détecté au moment de la compilation et les déplace à l'exécution.enum
, mais ce que vous décrivez n'est pas unenum
. Vous décrivez quelque chose de différent. L'ajout de médicaments génériques à l'énumération juste brouille la notion deenum
pour satisfaire les considérations pratiques de ce que vous voulez utiliser laenum
pour. Je pense que si vous voulez cette capacité, il doit être livré par quelques autres construire.enum
, mais permet-il de résoudre fondamentale restriction de langue? Mon intuition me dit pas. Les énumérations sont simples et résoudre un problème simple. Ils sont très bien comme ils sont et ne doit être laissé seul.enum
pour une raison. Leur travail consiste à énumérer une liste limitée de cas appartenant à une classe. Les gens ont redéfini dans des manières intelligentes, mais cela ne signifie pas que la fonction de conception de l'élan a changé.Option
ouProperty
classes de perdre leur type d'identité au moment de l'exécution.class Emun<E extends Emun<E>> { } abstract class Xenu<T> extends Emun<Xenu<T>> { abstract T convert(Object o); static Xenu<String> STRING = new Xenu<String>() { String convert(Object o) { return o.toString(); } }; String s = STRING.convert(3); }
BTW saviez-vous que toutes les langues avec un de vraiment compétent type de système, comme Haskell, ont aussi le type d'effacement?Object
et appliquer un aveugle de conversion? Cela fonctionne bien avec unString
mais qu'en est moins un exemple artificiel.class MyComplexClassConverter { MyComplexClass convert(Object o) { // lets hope I don't explode in your face }}
pour faire cela correctement java aurait à l'appui de la contravariance.interface Converter<IN, OUT> { OUT convert(IN in); } <E> Set<E> convertListToSet(List<E> in, Converter<? super List<E>, ? extends Set<E>> converter) { return converter.convert(in); }
Nous avons manuellement travail chaque fois que le type est consommé et qui les a produites, et de préciser les limites en conséquence.EARTH<EarthProperties>, MARS<MarsProperties>
Becasue "enum" est l'abréviation pour l'énumération.
C'est juste un ensemble de nommé constantes qui se mettent en place des nombres ordinaux pour rendre le code mieux lisible.
Je ne vois pas ce que la signification d'un type paramétré constante pourrait être.
java.lang.String
:public static final Comparator<String> CASE_INSENSITIVE_ORDER
. Vous voyez maintenant? 🙂CASE_INSENSITIVE_ORDER
... SiComparator<T>
ont été un enum, pourquoi ne pas avoir littéraux avec tout associée lié pour<T>
?Je pense que parce que, fondamentalement, les Énumérations ne peut pas être instanciée
Où placeriez-vous la classe T, si la JVM vous a permis de le faire?
L'énumération de données qui est censé être toujours les mêmes, ou au moins, qu'il ne changera pas dinamically.
nouveau MyEnum<>()?
Encore l'approche suivante peut être utile
setO()
méthode sur unenum
. Je considère que les énumérations, les constantes et pour moi qui implique immuable. Donc, même si c'est possible, je ne le ferais pas.