2

有人可以向我解释这种行为:

注意:在 SomeThingGeneric 中从未使用过 T

   public static class SomeThingGeneric<T> {
        public List<String> getSomeList() {
            return null;
        }
    }

final SomeThingGeneric<Object> someThingGenericObject = new SomeThingGeneric<Object>();
final SomeThingGeneric<?> someThingGenericWildcard    = new SomeThingGeneric<Object>();
final SomeThingGeneric someThingGenericRaw            = new SomeThingGeneric<Object>();

for (final String s : someThingGenericObject.getSomeList()) { }   // 1 - compiles
for (final String s : someThingGenericWildcard.getSomeList()) { } // 2 - compiles
for (final String s : someThingGenericRaw.getSomeList()) { }      // 3 - does not compile!

(1) 和 (2) 编译但 (3) 失败并显示以下消息:

incompatible types
found   : java.lang.Object
required: java.lang.String

如果有人想要完整的代码,这里是. 我已经在 J​​ava 5 和 6 中验证了这一点。

4

4 回答 4

4

好吧,尽管投反对票,但这是一个有趣的问题。我相信问题的答案在于JLS的这一部分:

未从其超类或超接口继承的原始类型 C的构造函数(第 8.8 节)、实例方法(第 8.4 节、第 9.4 节)或非静态字段(第 8.3 节)的类型是对应的原始类型在对应于 C 的泛型声明中擦除其类型。

实际上,在您通过原始类型访问它的情况下,您的方法public List<String> getSomeList会获得有效的签名。public List getSomeList因此,结果列表的列表迭代器然后“返回”对象而不是字符串。

于 2013-04-09T07:49:27.047 回答
3

代码可以分解为以下 SSCCE:

public static class SomeThingGeneric<T> {
    public List<String> getSomeList() {
        return null;
    }
}

public static void main(final String[] args) {
    final SomeThingGeneric someThingGenericRaw = new SomeThingGeneric<Object>();
    for (final String s : someThingGenericRaw.getSomeList()) { }        //  SAD compiler.  WTF?
}

这会导致编译器错误Type mismatch: cannot convert from element type Object to String

问题是:为什么会出现这个错误?T没有在 中的任何地方使用SomeThingGeneric,尤其是在getSomeList()方法的签名中。所以,当我们调用 时getSomeList(),我们应该得到一个List<String>. 然而,我们显然得到了一个原始List类型。


原因是类型擦除。从JLS

类型擦除还将构造函数或方法的签名(第 8.4.2 节)映射到没有参数化类型或类型变量的签名。

而且,a 的定义raw type说:

为了方便与非通用遗留代码的接口,可以使用参数化类型(§4.5)的擦除(§4.6)或元素类型为参数化类型的数组类型(§10.1)的擦除作为类型. 这种类型称为原始类型

因此,当使用原始类型时,它是应用了类型擦除的泛型类型。应用类型擦除时,所有方法签名都映射到没有类型参数或类型变量的类型。因此,List<String> getSomeList()示例中的方法会List getSomeList()导致显示的编译器错误。

于 2013-04-09T07:26:46.123 回答
3

答:当您将泛型类型实例化为原始类型时,它的所有类型实例都将被删除,原始类型无处不在(即使它们与类型参数无关,例如 Q 中的 T)。即原始类型是 100%“无泛型”。

原因:与前通用代码的向后兼容性。

于 2013-04-13T00:50:24.683 回答
0

因为我的意见是一个错误。因为它必须起作用。该方法的签名不使用泛型 T 类型。所以它必须编译。

将整个类标记为擦除,不要编译定义非常好的泛型方法,不好。

请报告。

于 2013-04-11T23:52:46.333 回答