对泛型类的非泛型引用会导致非泛型返回类型

时间:2009-01-16 00:33:29

标签: java generics

我有一个遗留类,该类本身不是通用的,但其方法之一返回类型使用泛型:

public class Thing {
    public Collection<String> getStuff() { ... }
}

getStuff()使用泛型返回字符串集合。因此,我可以迭代getStuff(),并且无需将元素强制转换为String

Thing t = new Thing();
for (String s: t.getStuff())  // valid
{ ... }

但是,如果我将Thing本身更改为通用,但保持其他所有内容相同:

public class Thing<T> {
    public Collection<String> getStuff() { ... }
}

然后继续使用Thing的非通用引用,getStuff()不再返回Collection<String>,而是返回非类型Collection。因此客户端代码无法编译:

Thing t = new Thing();
for (String s: t.getStuff())  // compiler complains that Object can't be cast to String
{ ... }

这是为什么?有哪些解决方法?

我的猜测是,通过使用对泛型类的非泛型引用,Java会关闭整个类的所有泛型。这很痛苦,因为现在我通过使Thing成为通用来破坏我的客户端代码。

编辑:我正在为上面示例代码中未列出的其他方法制作Thing泛型。我的问题是关于为什么不能做到这一点的教育。

3 个答案:

答案 0 :(得分:10)

好的,拿两个,我误解了你的问题。

当你将del Thing(这称为原始类型)而非Thing<?>参数化类型)删除时,Java编译器会删除所有内容泛型参数,甚至thogh(如你的情况),方法的泛型类型与类的泛型类型无关。

来自(优秀)Java Generics FAQ

Can I use a raw type like any other type?

  

原始类型的方法或构造函数具有在类型擦除后具有的签名。

这个看似无害且不引人注目的句子描述了有问题的行为。您使用Thing作为原始类型,因此返回类型为Collection(不是Collection<String>),因为这是类型擦除后的类型。

困惑?不奇怪。只需看看常见问题解答的大小。地球上可能有大约三个人理解Java泛型的全部含义。只需考虑我最喜欢的JDK声明:

Enum<T extends Enum<T>> 

(在常见问题解答中也有解释)。

答案 1 :(得分:0)

因擦除而失败。您可以在Java Tutorials

中详细了解相关信息

答案 2 :(得分:0)

我认为这是完全正常的。在我看来,使用Thing t = new Thing();对于泛型启用类是完全错误的。当编译器看到用作没有类型参数的类的泛型类时,它认为它必须擦除该类中的所有泛型类型。这就是你如何在新的java编译器和编译器中编译旧代码而不使用泛型,让旧代码使用通用的启用类(例如java.util.ArrayList)而没有任何问题。 (这就是java不需要像C#那样分离System.Collection.Generic.List和System.Collection.List)。您可以通过添加一个简单的类型参数Thing t = new Thing();来运行Thing<Object> t = new Thing<Object>();,只有java编译器需要的是确保您有意识地使用java通用。我永远不能责怪Java的强大向后兼容性。

我知道我有点迟了:D