162 votes

Pourquoi les littéraux d'énumération Java ne devraient-ils pas pouvoir 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 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>, à son tour, 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);

Mise à JOUR: Depuis la un exemple ci-dessus semble trop abstrait pour certains, voici un exemple de pourquoi je veux faire ce. Dans cet exemple, je veux utiliser

  • Les Enums, parce que je peux énumérer un ensemble fini de propriété touches
  • Les 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);
}

Personne n'a 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 cela? Avant de vous répondre, réfléchissez à 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 jette là où applicable (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 l' T getvalue() méthode. Le compilateur peut appliquer la conversion de type lors de l'appel d' String string = someClass.getValue(LITERAL1)

12voto

Martin Algesten Points 5915

La réponse est dans la question:

à cause de l'effacement des caractères

Aucune de ces deux méthodes n'est possible car le type d'argument est effacé.

 public <T> T getValue(MyEnum<T> param);
public T convert(Object);
 

Pour réaliser ces méthodes, vous pouvez cependant construire votre enum sous la forme:

 public enum MyEnum {
    LITERAL1(String.class),
    LITERAL2(Integer.class),
    LITERAL3(Object.class);

    private Class<?> clazz;

    private MyEnum(Class<?> clazz) {
      this.clazz = clazz;
    }

    ...

}
 

5voto

Parce que tu ne peux pas. Sérieusement. Cela pourrait être ajouté à la spécification de langue. Ça n'a pas été. Cela ajouterait une certaine complexité. Cet avantage de coût signifie que ce n'est pas une grande priorité.

0voto

nsfyn55 Points 4753

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.

Prenez un exemple d'un livre de texte enum. Ce n'est pas très utile ou cohérente:

public enum Planet<T>{
    Earth<Planet>,
    Venus<String>,
    Mars<Long>
    ...etc.
}

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

public enum BadIdea<T>{
   INSTANCE1<Long>,
   INSTANCE2<MyComplexClass>;
}

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 en MyComplexClass? 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.

0voto

raphw Points 6008

Pour répondre à votre question initiale: Oui, c'est un compilateur de limitation. Une énumération en Java comme

enum AnEnum { A, B }

est délactosé quelque chose de similaire comme

class AnEnum extends Enum<AnEnum> {
  public static final MyEnum A = new AnEnum(), B = new AnEnum();
}

tels que le compilateur Java serait en mesure de définir une énumération d'être générique. (Il est évident qu'en pensant au fait que la JVM n'est pas au courant de types génériques.)

C'est la mise en œuvre de choses et en regardant de ce côté, votre langue en fonction du sens. Cependant, à partir du langage Java point de vue, tout cela n'est rien, mais un détail d'implémentation. De la même manière que la JVM ne pas savoir sur les médicaments génériques, le langage Java ne sait pas sur enum constantes d'être des instances d'une classe. (La première déclaration n'est pas tout à fait vrai car il est un indicateur pour les énumérations, de cette façon, le Java runtime peut interdire la réflexion des accès de enum constructeurs qui, sinon, pourrait briser l'abstraction du modèle.) L'abstraction exige que les énumérations ne sont pas censés être des instances d'une classe, ils sont considérés comme de simples valeurs des constantes de l'énumération.

Considérons l'exemple suivant:

enum ExampleEnum {
  A {
    void foo() { 
      // do something
    }
  }, B
}

C'est une définition juridique d'un enum et vous pourriez vous attendre à être en mesure d'appeler ExampleEnum.A.foo(). Ce serait parfaitement type-safe, mais est pourtant interdit dans le langage Java pour la simple raison qu' A n'est pas considérée comme une instance d'une classe ExampleEnum comme indiqué ci-dessus. C'est un résultat de la façon dont le langage Java traite des énumérations.

De ce côté-ci de la définition de ce qu'est un enum doit représentent en fait, il ne serait ni raisonnable d'avoir un certain générique enum A<SomeType> comme elle le fait, par définition, pas de représenter son propre type et il ne serait donc pas visible. Et, dans cet esprit, il ne serait ni ajouter de sécurité du type.

Tout cela est cependant un point de vue sur Java, comme il l'est aujourd'hui. L'enum abstraction est déjà de type de fuites (rappelez-vous le drapeau) et vous pouvez aussi tout simplement exécuter

ExampleEnum.A.getClass().getDeclaredMethod("foo").invoke(ExampleEnum.A)

pour éviter le compilateur Java points de vue et de retour à l'instance spécifique de point de vue qui est appliquée par le runtime Java. Comme les génériques n'existent pas au moment de l'exécution, il n'y a cependant pas d'alternative à la limitation de vous nom.

Je voudrais cependant prétendre que vous avez un point intéressant. À partir d'un réalisateur de la vue, il serait au moins trivial à réaliser que la JVM n'auraient pas besoin d'être modifiées, et parce que le langage Java est déjà capable d'appliquer les vérifications de type pour les génériques. En fin de compte, le langage Java évolue toujours et je ne peux penser à des cas d'utilisation significative. Le principal objet de discussion serait bien de l'adresse de substituabilité comme vous le feriez pour briser l'hypothèse que l'un enum constante pourrait représenter l'enum type à n'importe quel endroit en raison de générique incompatibilités. Dans ce contexte, les génériques pourrait ajouter à type de confusion au lieu d'ajouter de sécurité du type. Une discussion de cette fonction principalement sur de déterminer si cet inconvénient est compensé par les avantages que vous avez déclaré.

-2voto

Ingo Points 21438

Becasue "enum" est l'abréviation de énumération. C'est juste un ensemble de constantes nommées qui se substituent aux nombres ordinaux pour rendre le code plus lisible.

Je ne vois pas ce que la signification voulue d'une constante paramétrée par type pourrait être.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X