Подтвердить что ты не робот

Enum.valueOf(класс <T> enumType, String name) вопрос

Я пытаюсь обойти ошибку компиляции ( "Связанное несоответствие:..." ), относящееся к динамическому просмотру enum.

В основном я хочу добиться чего-то вроде этого:

String enumName = whatever.getEnumName();
Class<? extends Enum<?>> enumClass = whatever.getEnumClass();
Enum<?> enumValue = Enum.valueOf(enumClass, enumName);

Что бы я ни делал, я всегда получаю ошибку компиляции. Честно говоря, дженерики и перечисления для меня совершенно разные...

Что я здесь делаю неправильно?

4b9b3361

Ответ 1

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

public static <T extends Enum<T>> T valueOf(
    Class<T> enumType,
    String name
);

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

public enum King{
    ELVIS
}

@SuppressWarnings({ "unchecked", "rawtypes" })
public static void main(final String[] args){
    final Class<? extends Enum> enumType = King.class;
    final Enum<?> theOneAndOnly = Enum.valueOf(enumType, "ELVIS");
    System.out.println(theOneAndOnly.name());
}

Вывод:

ЭЛВИС

Ответ 2

Проблема заключается в Class<? extends Enum<?>>. Мы хотим E extends Enum<E>, но мы не можем этого добиться, потому что у нас есть две разные подстановочные знаки.

Итак, нам нужно ввести общий параметр, который можно ввести путем вызова метода:

enum MyEnum {
    ME;
}

public class EnName {
    public static void main(String[] args) {
        Enum<?> value = of(MyEnum.class, "ME");
        System.err.println(value);
    }
    private static <E extends Enum<E>> E of(Class<E> clazz, String name) {
        E value = Enum.valueOf(clazz, name);
        return value;
    }
}

Но размышление грязно и очень редко, что вы хотите. Не делайте этого.

Ответ 3

На самом деле существует альтернативный подход: вы можете использовать Class.getEnumConstants и катить собственную реализацию Enum.valueOf, которая не имеет проблем с тем же типом. Недостатком является то, что вы возвращаете общий Enum<?>, но если бы вы знали, в каком типе вы вошли, вы все равно сможете использовать Enum.valueOf.

private static Enum<?> findEnumValue(Class<? extends Enum<?>> enumType, String value) {
    return Arrays.stream(enumType.getEnumConstants())
                 .filter(e -> e.name().equals(value))
                 .findFirst()
                 .orElse(null);
}

(Обратите внимание, что моя версия возвращает null, если нет такой константы, а не бросать IllegalArgumentException, но это тривиальная вещь для изменения.