【问题标题】:Unexpected "unchecked conversion" warning意外的“未经检查的转换”警告
【发布时间】:2014-06-20 13:56:38
【问题描述】:

以下代码导致未经检查的转换编译器警告 -

{
    List<String> first = first((Class)Integer.class);
}

private <T> List<String> first(Class<T> clazz) { return null; }

但是,以下代码没有任何警告 -

{
    List<String> second = second((Class)Integer.class);
}

private List<String> second(Class<?> clazz) { return null; }

总共有三个警告,前两个是我预料到的,但第三个没有意义 -

$ javac Test1.java -Xlint
    Test1.java:6: warning: [unchecked] unchecked conversion
    found   : java.lang.Class
    required: java.lang.Class<T>
    List<String> first = first((Class)Integer.class);
                               ^
    Test1.java:6: warning: [unchecked] unchecked method invocation: <T>first(java.lang.Class<T>) in Test1 is applied to (java.lang.Class)
    List<String> first = first((Class)Integer.class);
                              ^
    Test1.java:6: warning: [unchecked] unchecked conversion
    found   : java.util.List
    required: java.util.List<java.lang.String>
    List<String> first = first((Class)Integer.class);
                              ^
    3 warnings

编译器版本-

$ javac -version
    javac 1.6.0_45

我的问题是,为什么会出现第三个编译器警告?

【问题讨论】:

  • 第一个代码示例生成编译器警告。第二个(非常相似)没有。我想我们需要 Sherlock 来猜猜这里的问题是什么……
  • 我的猜测是传入一个原始类型Class(而不是Class&lt;?&gt;Class&lt;Integer&gt;)会使first 签名中的&lt;T&gt; 无效方法,并且由于某种原因导致整个方法调用被视为原始调用。因此,它不仅使&lt;T&gt; 无效,而且使返回类型中的&lt;String&gt; 无效。
  • 尝试从第一段代码中删除&lt;T&gt; ---private &lt;T&gt; List&lt;String&gt; first(Class&lt;T&gt; clazz) { return null; }
  • @VGR 是的,我进一步调查并发现了这个 -snipurl.com/unchecked 我是 Stackoverflow 的新手,所以不太确定它是如何工作的......你想发表评论吗完整的回复,以便我可以将其标记为答案?

标签: java generics jdk1.6 unchecked


【解决方案1】:

由于您使用预通用(原始)传递参数

first((Class)Integer.class)

而不是

first((Class<?>)Integer.class)

first 的返回类型被降级为前泛型 List 而不是 List&lt;String&gt;,并且使用 List(其中预期为 List&lt;String&gt;)会导致未经检查的转换警告。


Raw Types 上的 Java 文档说明:

原始类型出现在遗留代码中,因为许多 API 类(例如 Collections 类)在 JDK 5.0 之前不是通用的。当使用原始类型时,你基本上得到了前泛型行为——一个盒子给你对象。 为了向后兼容,允许将参数化类型分配给其原始类型:

...

但如果将原始类型分配给参数化类型,则会收到警告:

【讨论】:

  • 似乎为该调用关闭了(整个)泛型。 +1
  • @BheshGurung,是的。为了向后兼容,从将原始类型作为输入的运算符派生的任何类型都必须生成原始类型或非泛型类型。这样库就可以添加泛型,而预泛型(可能是类型不健全的)客户端代码仍然可以很好地针对它们进行编译。首次引入仿制药时,项目的零碎迁移是一个高度优先事项。
【解决方案2】:

我的猜测是,传入原始类型 Class(而不是 Class&lt;?&gt;Class&lt;Integer&gt;)会使 first 方法的签名中的 &lt;T&gt; 无效,并且对于某些导致整个方法调用被视为原始调用的原因。因此,它不仅使&lt;T&gt; 无效,而且还使返回类型中的&lt;String&gt; 无效。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-05
    • 1970-01-01
    相关资源
    最近更新 更多