【问题标题】:Calling Enum.<T>valueOf() giving unchecked cast warning, despite T being declared <T extends Enum<T>>调用 Enum.<T>valueOf() 给出未经检查的强制转换警告,尽管 T 被声明为 <T extends Enum<T>>
【发布时间】:2014-04-20 00:50:26
【问题描述】:

这一定是小事,但我不明白。

当它具有与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:\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?。这个枚举的类型是已知的。

【问题讨论】:

  • 我实际上应该返回T,而不是Enum,尽管这不会停止警告。

标签: java generics enums


【解决方案1】:

您应该调用getDeclaringClass(),这也将解决泛型问题(指定返回Class&lt;T&gt;)。在定义了自己的方法的枚举常量上调用 getClass() 实际上可以返回与枚举类型不同的类。

【讨论】:

【解决方案2】:

JavaDocs for Object.getClass() 指定:

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

泛型类型TerasureObject,所以for_value.getClass() 的返回类型是Class&lt;? extends Object&gt;不是Class&lt;T&gt;。尝试将其转换为 Class&lt;T&gt; 会导致未经检查的转换警告。

【讨论】:

  • 那么有没有办法避免未经检查的演员表?
  • 您可以将Class&lt;T&gt; clazz 参数传递给该方法——这将是标准方式。我认为您可以忽略警告(使用SuppressWarnings("unchecked")),但我必须考虑一下以确保。
【解决方案3】:

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

但是;

虽然getClass 被声明为返回Class&lt;?&gt;,但它的规范是一个特殊情况,you can assign the result of it to a Class&lt;? extends T&gt; without the explicit class

实际结果类型为Class&lt;? extends |X|&gt; ...

这很好,但第一个问题是它返回了 X 的擦除,这意味着原始类型。所以下面的赋值需要一个未经检查的演员表:

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

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

不幸的是,因为 Enum 具有递归泛型 (E extends Enum&lt;E&gt;),所以通配符不好,所以你不能用它调用 valueOf

在我编辑此内容时,有人发布了正确答案,即使用Enum#getDeclaringClass

【讨论】:

  • 是的,我在玩弄它,但它失败了。这是 Enum 的声明方式,这很痛苦,我忘记了这一点。 getClass 返回一个原始的 ? extends Enum。我马上编辑。
  • 递归泛型很痛苦。
  • 感谢@Radiodef 的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-04-02
  • 1970-01-01
  • 2021-08-31
  • 2013-10-02
  • 1970-01-01
  • 2010-09-22
  • 1970-01-01
相关资源
最近更新 更多