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

Как получить значение Enum, если я не знаю класс во время компиляции?

Я пытаюсь сделать следующее:

Class<?> cls = unknownClass;
if(cls.isEnum()){
    @SuppressWarnings("unchecked")
    Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) cls;
    Object val = Enum.valueOf(enumClass, "NAME1");
}

Но я получаю следующую ошибку:

Bound mismatch: The generic method valueOf(Class<T>, String) of type Enum<E> is 
not applicable for the arguments (Class<capture#5-of ? extends Enum<?>>, String). 
The inferred type capture#5-of ? extends Enum<?> is not a valid substitute for 
the bounded parameter <T extends Enum<T>>   

Может кто-нибудь сказать мне, что я делаю неправильно?

4b9b3361

Ответ 1

Учитывая, что приведение не будет действительно проверять вещи, я бы пошел с полностью необработанной версией:

if (cls.isEnum()){
    @SuppressWarnings("unchecked")
    Object val = Enum.valueOf(cls, "NAME1");
}

Это похоже на работу. Полный пример:

public class Test
{
    enum Foo
    {
        BAR, BAZ
    }


    public static void main(String[] args)
    {
        @SuppressWarnings("rawtypes")
        Class cls = Foo.class;

        if (cls.isEnum())
        {        
            @SuppressWarnings("unchecked")
            Object value = Enum.valueOf(cls, "BAR");
            System.out.println(value);
        }
    }
}

Ответ 2

Проблема в том, что у вас есть два ?, и они могут быть разными, и они должны быть одинаковыми.

Вам либо нужно использовать не общий тип объявления общего типа, например

public static <T extends Enum<T>> T val(Class<T> cls) {
    if(cls.isEnum()) { // is redundant when the compiler checks this.
        @SuppressWarnings("unchecked")
        Class<T> enumClass = (Class<T>) cls;
        T val = Enum.valueOf(enumClass, "NAME1");
        return val;
    }
    return null;
}

Однако вызов этого метода также является кошмаром.;)

Ответ 3

Class.getEnumConstants предоставит все перечисления, которые вы можете затем найти тот, который вас интересует.

Изменение кода Jon:

public class Test {
    private enum Foo {
        BAR, BAZ
    } 

    public static void main(String[] args) {
        Class<?> cls = Foo.class;

        if (cls.isEnum()) { 
            for (Object constant : cls.getEnumConstants()) { 
                Enum<?> enumConstant = (Enum<?>)constant;
                if (enumConstant.name().equals("BAR")) {
                    System.out.println(constant);
                    break;
                }
            }
        }
    }
}

В Java SE 8 вы, возможно, сможете сделать что-то умное с помощью лямбда и абстрактного потока управления.

Примечание:

  • Отражение - это почти всегда плохая идея.
  • Нет необходимости в непроверенном предупреждении или подавлении этих действительных предупреждений.
  • Не нужно использовать rawtypes (который когда-либо написание и семантика) предупреждает или подавляет эти действительные предупреждения.
  • Не нужно необоснованного разглагольствования.
  • Не нужно понижать этот ответ.

Ответ 4

Использование исходного типа является хорошим. Хотя Java не захотела добавлять сырой тип, было доказано, что оно является необходимым и незаменимым, помимо проблем с обратной совместимостью.

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

Ответ 5

    class EnumValues<P extends Enum<P>>
    {
        public static <P extends Enum<P>> P [] getValues( Class<P> keyType)
        {
            return keyType.getEnumConstants();
        }
    }

Использование:

    Class cls = Thread.State.class;
    for( Enum en : EnumValues.getValues( cls)) 
        System.out.println( en.name());