调用枚举。<t> valueOf()给出未经检查的强制警告,尽管T被声明为<t extends =“”enum <t =“”>&gt; </t> </t>

时间:2014-04-19 16:19:11

标签: java generics enums

这必须是小事,但我没有得到它。

为什么这会导致未经检查的强制转换编译器警告,因为它与Enum valueOf具有完全相同的通用声明?

public static final <T extends Enum<T>> Enum toValue(T for_value, String value)  {
   try  {
      return  Enum.<T>valueOf((Class<T>)for_value.getClass(), value);
   }  catch(RuntimeException rx)  {
      throw  new IllegalArgumentException(value);
   }
}

编译器警告:

R:\jeffy\programming\sandbox\xbnjava\xbn\util\EnumUtil.java:92: 
warning: [unchecked] unchecked cast
         Enum.<T>valueOf((Class<T>)for_value.getClass(), value);
                                                     ^
  required: Class<T>
  found:    Class<CAP#1>
  where T is a type-variable:
    T extends Enum<T> declared in method <T>toValue(T,String,String)
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Enum from capture of ? extends Enum
R:\jeffy\programming\sandbox\xbnjava\xbn\util\EnumUtil.java:98: error: missing return statement
   }
   ^
1 error
1 warning

也会在函数调用中删除一个或两个泛型,例如

Enum.valueOf(for_value.getClass(), value);

这是我发现的最接近的问题: Enum.valueOf throws a warning for unknown type of class that extends Enum? 。这个枚举的类型是已知的。

3 个答案:

答案 0 :(得分:8)

您应该调用getDeclaringClass(),这也将修复泛型问题(指定返回Class<T>)。使用自己定义的方法在枚举常量上调用getClass()实际上可以从枚举类型返回不同的类。

答案 1 :(得分:1)

getClass调用是生成未经检查的警告,而不是Enum#valueOf。原因是getClass返回Class<? extends T>而不是Class<T>。请记住,for_value实际上可能是T的子类。

然而;

虽然宣布getClass返回Class<?>,但规范却是you can assign the result of it to a Class<? extends T> without the explicit class

  

实际结果类型为Class<? extends |X|> ...

这很好,但第一个问题是它返回X的擦除,这意味着原始类型。因此,以下任务需要未经检查的演员:

@SuppressWarnings("unchecked")
Class<? extends E> cls = (Class<? extends E>)for_value.getClass();

由于Enum的语言限制,这样做是安全的:不可能使用可能会破坏此声明的声明来制作枚举。

不幸的是因为Enum具有递归泛型(E extends Enum<E>),所以通配符很糟糕,所以你不能用它调用valueOf

在我编辑时,有人发布了使用Enum#getDeclaringClass的正确答案。

答案 2 :(得分:1)

JavaDocs for Object.getClass()指定:

  

实际结果类型是Class,其中| X |是擦除调用getClass的表达式的静态类型。

通用类型T的{​​{3}}为Object,因此for_value.getClass()的返回类型为Class<? extends Object>不是 Class<T>。试图将其投射到Class<T>是为了给你未经检查的投射警告。