2011-01-20 4 views
8

Это похоже, но не совсем такой же, как Java: instantiating an enum using reflectionJava: отражение, чтобы получить Enum

У меня есть Map<Enum<?>, FooHandler>, что я хочу использовать для отображения Enum с (я не забочусь, какой тип или даже если они тот же тип, до тех пор, пока они являются константами перечисления) для моего класса FooHandler.

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

static private <E extends Enum<E>> E getEnum(String enumFullName) { 
    // see https://stackoverflow.com/questions/4545937/ 
    String[] x = enumFullName.split("\\.(?=[^\\.]+$)"); 
    if (x.length == 2) 
    { 
    String enumClassName = x[0]; 
    String enumName = x[1]; 
    try { 
     Class<E> cl = (Class<E>)Class.forName(enumClassName); 
     // #1       

     return Enum.valueOf(cl, enumName); 
    } 
    catch (ClassNotFoundException e) { 
     e.printStackTrace(); 
    } 
    } 
    return null; 
} 

public void someMethod(String enumName, String fooHandlerName) 
{ 
    FooHandler fooHandler = getFooHandler(fooHandlerName); 
    Enum e = getEnum(enumName); 
    // #2 

    map.put(e, fooHandler); 
} 

Предупреждение # 1: Переполнение отлитых Предупреждения # 2: Enum является исходным типом.

Я получаю # 1 и могу просто поставить предупреждение, я полагаю, но, похоже, я не могу бить предупреждение №2; Я пробовал Enum<?>, и это просто дает мне ошибку о несоответствии привязки общего типа.


Альтернативные реализации, которые хуже: До моего <E extends Enum<E>> родового возвращаемого значения, я попытался возвращения Enum и он не работает; Я получил эти предупреждения/ошибки:

static private Enum<?> getEnum(String enumFullName) { 
    ... 

Class<?> cl = (Class<?>)Class.forName(enumClassName); 
    // 1 
return Enum.valueOf(cl, enumName); 
    // 2 
} 
  1. предупреждения:

    - Type safety: Unchecked cast from Class<capture#3-of ?> to Class<Enum> 
        - Enum is a raw type. References to generic type Enum<E> should be parameterized 
        - Enum is a raw type. References to generic type Enum<E> should be parameterized 
        - Unnecessary cast from Class<capture#3-of ?> to Class<?> 
    
  2. ошибки:

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

и это:

static private Enum<?> getEnum(String enumFullName) { 
    ... 
    Class<Enum<?>> cl = (Class<Enum<?>>)Class.forName(enumClassName); 
    // 1 
    return Enum.valueOf(cl, enumName); 
    // 2 
  1. предупреждение: Type safety: Unchecked cast from Class<capture#3-of ?> to Class<Enum<?>>
  2. ошибка: Bound mismatch: The generic method valueOf(Class<T>, String) of type Enum<E> is not applicable for the arguments (Class<Enum<?>>, String). The inferred type Enum<?> is not a valid substitute for the bounded parameter <T extends Enum<T>>

ответ

6

Для # 1 нет никакого решения, кроме SuppressWarnings("unchecked").

Для # 2 есть проблема с декларацией:

static private <E extends Enum<E>> E getEnum(String enumFullName) 

Вы можете вернуть E, но нет никакого способа для компилятора, чтобы определить E. Нет аргументов типа E или Class<E> или что-то еще, что позволит это сделать. Вы можете написать это, но где-то будет неконтролируемый бросок, и когда вы его назовете, вы можете получить ClassCastException. Так что не делай этого.

Просто измените его в

static private Enum<?> getEnum(String enumFullName) 

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

+0

Вы можете вернуть 'E', и для его компилятора есть способ определить его ... он, как и аргументы типа всех общих методов, определяется на сайте вызова. Часто он определяется на основе некоторых аргументов, переданных методу (и обычно имеет смысл использовать общие методы таким образом), но он также может быть определен на основе использования возвращаемого значения. Как я уже сказал, обычно это не имеет смысла делать, учитывая, что это часто «ClassCastException» просто ждет. – ColinD

+0

Согласовано. Я изменил его 'статический частный Enum getEnum (String enumFullName) { ... @SuppressWarnings ("непроверенных") \t \t конечный класс сл = (класс ) Class.forName (enumClassName); \t \t @SuppressWarnings ("unchecked") \t \t final Enum result = Enum.valueOf (cl, enumName); \t \t результат возврата; \t} ' , но на самом деле мне лучше всего аннотировать весь метод с помощью SuppressWarnings, поскольку он может вызывать исключение ClassCastException, если имя класса не обозначает Enum. – maaartinus

+0

«Просто измените его на ... Enum » - это не работает, я пробовал его заранее, и это еще хуже, оно дает ошибку. –

5

Подпись

static private <E extends Enum<E>> getEnum(String enumFullName) 

не делает вам никакой пользы здесь.

<E extends Enum<E>> позволяет вызывающую методе, чтобы присвоить результат getEnum любого enum типа они хотят без литья:

SomeEnum e = getEnum("com.foo.SomeOtherEnum.SOMETHING"); // ClassCastException! 

Однако, это не имеет никакого смысла ... если абонент знал, какой именно тип enum метод вернется, они могут сделать что-то более разумное, как SomeEnum.valueOf("SOMETHING").

Единственное, что имеет смысл здесь для getEnum просто вернуться Enum<?>, что кажется, что вы действительно хотите делать в любом случае:

static private Enum<?> getEnum(String enumFullName) { 
    String[] x = enumFullName.split("\\.(?=[^\\.]+$)"); 
    if(x.length == 2) { 
    String enumClassName = x[0]; 
    String enumName = x[1]; 
    try { 
     @SuppressWarnings("unchecked") 
     Class<Enum> cl = (Class<Enum>) Class.forName(enumClassName); 
     return Enum.valueOf(cl, enumName); 
    } 
    catch(ClassNotFoundException e) { 
     e.printStackTrace(); 
    } 
    } 
    return null; 
} 

выше компилируется без предупреждений и работает должным образом. Предупреждение отбрасывается до Class<Enum>, потому что мы знаем, что это небезопасно, и что Enum.valueOf взорвется, если класс с данным именем не является классом enum, и это то, что мы хотим сделать.

+0

«Просто измените его на ... Enum » - это не работает, я пробовал его заранее, и это еще хуже, оно дает ошибку. –

+0

@Jason S: Nevermind, как комментировал @maaartinus, используя 'Class ' как тип класса, который вы кладете, а не 'Class >' или какой-то вариант, похоже, работает. – ColinD

Смежные вопросы