有人可以向我解释这种行为:
注意:T从未在SomeThingGeneric中使用
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
如果有人想要完整的代码,here it is。我已经在Java 5和6中验证了这一点。
答案 0 :(得分:4)
嗯,这是一个有趣的问题,尽管这是一个有趣的问题。我相信这个问题的答案在于JLS的这一部分:
构造函数的类型(§8.8),实例方法(§8.4,§9.4),或者 非静态字段(第8.3节)未从中继承的原始类型C的M. 它的超类或超接口是对应的原始类型 在相应的通用声明中擦除其类型 下进行。
实际上,您的方法public List<String> getSomeList
会在您通过原始类型访问它的方案中获得public List getSomeList
的有效签名。因此,结果列表的列表迭代器然后“返回”对象而不是字符串。
答案 1 :(得分: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
。但是,我们显然得到了原始的List<String> getSomeList()
类型。
原因是类型擦除。来自JLS:
类型擦除还会将构造函数的签名(第8.4.2节)或方法映射到没有参数化类型或类型变量的签名。
并且,the definition of a raw type
说:
为了便于与非泛型遗留代码接口,可以使用参数化类型的擦除(§4.6)(§4.5)或数组类型的擦除( §10.1)其元素类型是参数化类型。 这种类型称为原始类型。
因此,在使用原始类型时,应用了类型擦除的泛型类型。应用类型擦除时,所有方法签名都映射到没有类型参数或类型变量的类型。因此,示例中的方法List getSomeList()
变为{{1}},导致显示的编译器错误。
答案 2 :(得分:3)
答案:当您将泛型类型实例化为原始类型时,将删除其所有类型实例化,从而将原始类型保留在任何位置(即使它们与类型参数无关,例如Q中的T)。即原始类型是100%“无泛型”。
原因:与通用前代码的向后兼容性。
答案 3 :(得分:0)
我认为这是一个错误。因为它必须工作。该方法的签名不使用通用T类型。所以它必须编译。
将整个类标记为擦除,不编译非常好的通用方法,不好。
请报告。