Переопределить valueof () и toString () в перечислении Java - PullRequest
109 голосов
/ 12 марта 2012

Значения в моем enum - это слова, в которых должны быть пробелы, но в перечислениях не может быть пробелов в их значениях, поэтому все они сгруппированы. Я хочу переопределить toString(), чтобы добавить эти пробелы, где я говорю это.

Я также хочу, чтобы перечисление предоставляло правильное перечисление, когда я использую valueOf() в той же строке, к которой я добавил пробелы.

Например:

public enum RandomEnum
{
     StartHere,
     StopHere
}

Вызов toString() на RandomEnum, значение которого StartHere, возвращает строку "Start Here". Вызов valueof() для этой же строки ("Start Here") возвращает значение перечисления StartHere.

Как я могу это сделать?

Ответы [ 7 ]

178 голосов
/ 12 марта 2012

Вы можете попробовать этот код. Поскольку вы не можете переопределить метод valueOf, вы должны определить пользовательский метод (getEnum в приведенном ниже примере кода), который возвращает нужное вам значение, и изменить ваш клиент для использования этого метода.

public enum RandomEnum {

    StartHere("Start Here"),
    StopHere("Stop Here");

    private String value;

    RandomEnum(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }

    @Override
    public String toString() {
        return this.getValue();
    }

    public static RandomEnum getEnum(String value) {
        for(RandomEnum v : values())
            if(v.getValue().equalsIgnoreCase(value)) return v;
        throw new IllegalArgumentException();
    }
}
22 голосов
/ 20 февраля 2014

Попробуйте, но я не уверен, что это будет работать везде:)

public enum MyEnum {
    A("Start There"),
    B("Start Here");

    MyEnum(String name) {
        try {
            Field fieldName = getClass().getSuperclass().getDeclaredField("name");
            fieldName.setAccessible(true);
            fieldName.set(this, name);
            fieldName.setAccessible(false);
        } catch (Exception e) {}
    }
}
10 голосов
/ 06 октября 2015

Как насчет реализации Java 8?(null может быть заменен на Enum по умолчанию)

public static RandomEnum getEnum(String value) {
    List<RandomEnum> list = Arrays.asList(RandomEnum.values());
    return list.stream().filter(m -> m.value.equals(value)).findAny().orElse(null);
}

Или вы можете использовать:

...findAny().orElseThrow(NotFoundException::new);
10 голосов
/ 27 ноября 2012

Вы можете использовать статическую карту в вашем перечислении, которая отображает строки в константы перечисления. Используйте его в статическом методе getEnum. Это пропускает необходимость перебирать перечисления каждый раз, когда вы хотите получить их из значения String.

public enum RandomEnum {

    StartHere("Start Here"),
    StopHere("Stop Here");

    private final String strVal;
    private RandomEnum(String strVal) {
        this.strVal = strVal;
    }

    public static RandomEnum getEnum(String strVal) {
        if(!strValMap.containsKey(strVal)) {
            throw new IllegalArgumentException("Unknown String Value: " + strVal);
        }
        return strValMap.get(strVal);
    }

    private static final Map<String, RandomEnum> strValMap;
    static {
        final Map<String, RandomEnum> tmpMap = Maps.newHashMap();
        for(final RandomEnum en : RandomEnum.values()) {
            tmpMap.put(en.strVal, en);
        }
        strValMap = ImmutableMap.copyOf(tmpMap);
    }

    @Override
    public String toString() {
        return strVal;
    }
}

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

Кстати - этот тип 'ImmutableMap' взят из API гуавы Google, и я определенно рекомендую его в подобных случаях.


РЕДАКТИРОВАТЬ - По комментариям:

  1. В этом решении предполагается, что каждое назначенное строковое значение уникально и не равно нулю. Учитывая, что создатель перечисления может управлять этим, и что строка соответствует уникальному & ненулевому значению перечисления, это выглядит как безопасное ограничение.
  2. Я добавил метод toSTring (), как было предложено в вопросе
2 голосов
/ 24 ноября 2017

У вас все еще есть возможность реализовать в своем перечислении это:

public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name){...}
2 голосов
/ 27 июня 2012

Ниже приведена хорошая общая альтернатива valueOf ()

public static RandomEnum getEnum(String value) {
  for (RandomEnum re : RandomEnum.values()) {
    if (re.description.compareTo(value) == 0) {
      return re;
    }
  }
  throw new IllegalArgumentException("Invalid RandomEnum value: " + value);
}
2 голосов
/ 12 марта 2012

Я не думаю, что вы собираетесь заставить valueOf («Начать здесь») работать.Но что касается пробелов ... попробуйте следующее ...

static private enum RandomEnum {
    R("Start There"), 
    G("Start Here"); 
    String value;
    RandomEnum(String s) {
        value = s;
    }
}

System.out.println(RandomEnum.G.value);
System.out.println(RandomEnum.valueOf("G").value);

Start Here
Start Here
...