呼叫枚举。<T>valueOf() 给出未经检查的强制转换警告,尽管 T 被声明为 <T 扩展枚举<T>>



这必须是一些小东西,但我不明白。

当它具有与EnumvalueOf完全相同的泛型声明时,为什么会导致未检查的强制转换编译器警告?

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:jeffyprogrammingsandboxxbnjavaxbnutilEnumUtil.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:jeffyprogrammingsandboxxbnjavaxbnutilEnumUtil.java:98: error: missing return statement
   }
   ^
1 error
1 warning

它也发生在从函数调用中删除一个或两个泛型中,例如

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

这是我发现的最接近的问题:Enum.valueOf为扩展Enum的未知类型的类抛出警告。此枚举的类型是已知的。

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

Object.getClass()的JavaDocs指定:

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

泛型类型T的擦除是Object,因此for_value.getClass()的返回类型是Class<? extends Object>而不是Class<T>。尝试将其强制转换为Class<T>会给您未检查的强制转换警告。

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

然而;

虽然getClass被声明为返回Class<?>,但它的规范是特殊情况,您可以将其结果分配给Class<? extends T>,而不需要显式类:

实际结果类型为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

最新更新