Могу ли я добавлять и удалять элементы перечисления во время выполнения в Java

Можно добавлять и удалять элементы из перечисления в Java во время выполнения?

Например, могу ли я прочитать в аргументах label и constructor перечисления из файла?


@saua, это просто вопрос о том, действительно ли это можно сделать из интереса. Я надеялся, что будет какой-то аккуратный способ изменить исполняемый байт-код, возможно, используя BCEL или что-то в этом роде. Я также рассмотрел этот вопрос, потому что понял, что я не совсем уверен, когда нужно использовать перечисление.

Я уверен, что правильным ответом будет использование коллекции, которая обеспечила бы уникальность вместо перечисления, если я хочу иметь возможность безопасно изменять содержимое во время выполнения.

Ответ 1

Нет, перечисления должны быть полным статическим перечислением.

Во время компиляции вам может потребоваться сгенерировать ваш файл enum.java из другого исходного файла. Вы даже можете создать такой файл .class, как это.

В некоторых случаях вам может потребоваться набор стандартных значений, но разрешить расширение. Обычный способ сделать это - interface для интерфейса и enum, который реализует это interface для стандартных значений. Конечно, вы теряете возможность switch, когда у вас есть только ссылка на interface.

Ответ 2

За занавеской перечисления представляют собой POJO с частным конструктором и кучей публичных статических конечных значений типа перечисления (см. здесь для пример). Фактически, вплоть до Java5, было сочтено, что лучше всего создать собственное перечисление таким образом, а Java5 представило ключевое слово enum в качестве сокращенного. Подробнее см. Источник Enum <T> .

Поэтому не должно возникнуть проблемы с написанием собственного "TypeSafeEnum" с открытым статическим окончательным массивом констант, которые считываются конструктором или передаются ему.

Также сделайте себе одолжение и переопределите equals, hashCode и toString и, если возможно, создайте метод values

Вопрос заключается в том, как использовать такое динамическое перечисление... вы не можете прочитать значение "PI = 3.14" из файла для создания enum MathConstants, а затем продолжить и использовать MathConstants.PI, где хотите..

Ответ 3

Мне нужно было сделать что-то подобное (для целей тестирования), и я наткнулся на это - EnumBuster: http://www.javaspecialists.eu/archive/Issue161.html

Он позволяет добавлять, удалять и восстанавливать значения перечислений.

Изменить: я только начал использовать это и обнаружил, что для java 1.5 есть небольшие изменения, которые я сейчас застрял:

  • Добавить массив copyOf статических вспомогательных методов (например, взять эти версии 1.6: http://www.docjar.com/html/api/java/util/Arrays.java.html)
  • Измените EnumBuster.undoStack на стек <Memento>
    • В undo() измените значение undoStack.poll() на undoStack.isEmpty()? null: undoStack.pop();
  • Строка VALUES_FIELD должна быть "ENUM $VALUES" для перечислений java 1.5, которые я пробовал до сих пор.

Ответ 4

Я столкнулся с этой проблемой на формирующем проекте моей молодой карьеры.

Подход, который я принял, состоял в том, чтобы сохранить значения и имена перечисления извне, и конечной целью было уметь писать код, который был как можно ближе к языку enum.

Я хотел, чтобы мое решение выглядело так:

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));

И у меня получилось что-то вроде этого:

// 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"));

Поскольку мои требования заключались в том, что во время выполнения было необходимо добавить участников в перечисление, я также реализовал эту функциональность:

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

Я назвал его шаблоном Dynamic Enumeration, и вы прочитали о исходном проекте и его пересмотренное издание.

Разница между двумя заключается в том, что пересмотренное издание было разработано после того, как я действительно начал проверять OO и DDD. Первый, который я разработал, когда я все еще писал номинально процедурный DDD, под давлением времени не менее.

Ответ 5

Вы можете загрузить Java-класс из источника во время выполнения. (Использование JCI, BeanShell или JavaCompiler)

Это позволит вам изменить значения Enum, как вы пожелаете.

Примечание: это не изменило бы классы, которые ссылались на эти перечисления, поэтому это может быть не очень полезно в действительности.

Ответ 6

Вы можете попытаться присвоить свойства ENUM, который вы пытаетесь создать, и статически конструировать с помощью загруженного файла свойств. Большой взлом, но он работает:)