Java: отражение, чтобы получить Enum - PullRequest
8 голосов
/ 20 января 2011

Это похоже, но не совсем то же самое, что и Java: создание экземпляра перечисления с использованием отражения

У меня есть Map<Enum<?>, FooHandler>, который я хочу использовать для сопоставления Enum s (мне все равно, какой тип или даже если они того же типа, только если они являются константами 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>>

Ответы [ 2 ]

6 голосов
/ 20 января 2011

подпись

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, и это то, что мы хотим делаем.

6 голосов
/ 20 января 2011

Для # 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)

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

...