Могу ли я добавлять и удалять элементы перечисления во время выполнения в Java - PullRequest
54 голосов
/ 26 января 2009

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

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


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

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

Ответы [ 6 ]

40 голосов
/ 26 января 2009

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

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

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

13 голосов
/ 26 января 2009

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

Так что не должно быть никаких проблем написать свой собственный TypeSafeEnum с общедоступным статическим окончательным массивом констант, которые считываются конструктором или передаются ему.

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

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

9 голосов
/ 15 марта 2010

Мне нужно было сделать что-то вроде этого (для целей модульного тестирования), и я столкнулся с этим - 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, которые я пробовал до сих пор
6 голосов
/ 26 января 2009

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

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

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

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

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

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

Я назвал его «шаблоном» динамического перечисления, и вы прочитали о оригинальном дизайне и его пересмотренном издании .

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

0 голосов
/ 26 января 2009

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

0 голосов
/ 26 января 2009

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

Это позволит вам изменять значения Enum по вашему желанию.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...