web-dev-qa-db-fra.com

Puis-je ajouter et supprimer des éléments d'énumération lors de l'exécution dans Java

Il est possible d'ajouter et de supprimer des éléments d'une énumération dans Java lors de l'exécution?

Par exemple, pourrais-je lire les étiquettes et les arguments du constructeur d'une énumération dans un fichier?


@saua, c'est juste une question de savoir si cela peut vraiment être fait par intérêt. J'espérais qu'il y aurait une bonne façon de modifier le bytecode en cours d'exécution, peut-être en utilisant BCEL ou quelque chose. J'ai également suivi avec cette question parce que je me suis rendu compte que je n'étais pas totalement sûr du moment où une énumération devait être utilisée.

Je suis assez convaincu que la bonne réponse serait d'utiliser une collection qui garantisse l'unicité au lieu d'une énumération si je veux pouvoir modifier le contenu en toute sécurité au moment de l'exécution.

55
brabster

Non, les énumérations sont censées être une énumération statique complète.

Au moment de la compilation, vous souhaiterez peut-être générer votre fichier .Java enum à partir d'un autre fichier source quelconque. Vous pouvez même créer un fichier .class comme celui-ci.

Dans certains cas, vous pouvez souhaiter un ensemble de valeurs standard mais autoriser l'extension. La façon habituelle de le faire est d'avoir un interface pour l'interface et un enum qui implémente ce interface pour les valeurs standard. Bien sûr, vous perdez la capacité de switch lorsque vous n'avez qu'une référence à interface.

41

Derrière le rideau, les énumérations sont des POJO avec un constructeur privé et un tas de valeurs finales statiques publiques du type de l'énumération (voir ici pour un exemple). En fait, jusqu'à Java5, il était considéré comme la meilleure pratique de créer votre propre énumération de cette façon, et Java5 a introduit le mot clé enum comme raccourci. Voir la source de Enum <T> pour en savoir plus.

Il ne devrait donc y avoir aucun problème à écrire votre propre "TypeSafeEnum" avec un tableau final statique public de constantes, qui sont lues par le constructeur ou transmises à lui.

Rendez-vous également service et remplacez equals, hashCode et toString, et si possible créez une méthode values

La question est de savoir comment utiliser une telle énumération dynamique ... vous ne pouvez pas lire la valeur "PI = 3.14" d'un fichier pour créer enum MathConstants puis allez-y et utilisez MathConstants.PI où tu veux...

13
Yuval

Je devais faire quelque chose comme ça (à des fins de test unitaire), et je suis tombé sur cela - l'EnumBuster: http://www.javaspecialists.eu/archive/Issue161.html

Il permet aux valeurs d'énumération d'être ajoutées, supprimées et restaurées.

Edit : Je viens juste de commencer à l'utiliser, et j'ai constaté qu'il y avait de légères modifications nécessaires pour Java 1.5, avec lequel je suis actuellement coincé:

  • Ajoutez des méthodes d'assistance statique de copie de tableau (par exemple, prenez ces versions 1.6: http://www.docjar.com/html/api/Java/util/Arrays.Java.html )
  • Remplacez EnumBuster.undoStack par un Stack<Memento>
    • Dans undo (), remplacez undoStack.poll () par undoStack.isEmpty ()? null: undoStack.pop ();
  • La chaîne VALUES_FIELD doit être "ENUM $ VALUES" pour les énumérations Java 1.5 que j'ai essayées jusqu'à présent).
9
Andy

J'ai rencontré ce problème sur le projet formateur de ma jeune carrière .

L'approche que j'ai adoptée était de sauvegarder les valeurs et les noms de l'énumération en externe, et l'objectif final était de pouvoir écrire du code qui ressemblait le plus possible à une énumération de langage.

Je voulais que ma solution ressemble à ceci:

enum HatType
{
    BASEBALL,
    BRIMLESS,
    INDIANA_JONES
}

HatType mine = HatType.BASEBALL;

// prints "BASEBALL"
System.out.println(mine.toString());

// prints true
System.out.println(mine.equals(HatType.BASEBALL));

Et je me suis retrouvé avec quelque chose comme ça:

// in a file somewhere:
// 1 --> BASEBALL
// 2 --> BRIMLESS
// 3 --> INDIANA_JONES

HatDynamicEnum hats = HatEnumRepository.retrieve();

HatEnumValue mine = hats.valueOf("BASEBALL");

// prints "BASEBALL"
System.out.println(mine.toString());

// prints true
System.out.println(mine.equals(hats.valueOf("BASEBALL"));

Étant donné que mes exigences étaient qu'il devait être possible d'ajouter des membres à l'énumération au moment de l'exécution, j'ai également implémenté cette fonctionnalité:

hats.addEnum("BATTING_PRACTICE");

HatEnumRepository.storeEnum(hats);

hats = HatEnumRepository.retrieve();

HatEnumValue justArrived = hats.valueOf("BATTING_PRACTICE");
// file now reads:
// 1 --> BASEBALL
// 2 --> BRIMLESS
// 3 --> INDIANA_JONES
// 4 --> BATTING_PRACTICE

Je l'ai surnommé le "modèle" d'énumération dynamique, et vous lisez la conception originale et son édition révisée .

La différence entre les deux est que l'édition révisée a été conçue après que j'ai vraiment commencé à grok OO et DDD. La première que j'ai conçue quand j'écrivais encore un DDD procédural nominal, sous la pression du temps, pas moins .

6
moffdub

Vous pouvez essayer d'assigner des propriétés à l'ENUM que vous essayez de créer et de le contracter statiquement en utilisant un fichier de propriétés chargé. Big hack, mais ça marche :)

0
Eldelshell

Vous pouvez charger une Java à partir de la source lors de l'exécution. (Utilisation de JCI, BeanShell ou JavaCompiler)

Cela vous permettrait de modifier les valeurs Enum comme vous le souhaitez.

Remarque: cela ne changerait aucune classe faisant référence à ces énumérations, ce qui pourrait ne pas être très utile en réalité.

0
Peter Lawrey