2009-01-16 55 views
8

我有一个传统类的类本身不是一个通用的,但它的方法返回类型使用泛型:非一般引用泛型类导致非泛型返回类型

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通用的另一种方法,没有在上面的示例代码中列出。我的问题是教育,为什么不能做到上述。

回答

10

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

当你delcare Thing(这被称为原始类型),而不是Thing<?>参数化类型)Java编译器剔除掉所有通用参数,甚至thogh(如你的情况)泛型类型的方法与类的泛型无关。

从(优秀)Java Generics FAQ

Can I use a raw type like any other type?

方法或原始类型的构造有,他们将不得不类型擦除后的签名。

这看似无伤大雅和不显眼的句子描述了有问题的行为。您使用Thing作为原始类型,因此返回类型为Collection(不是Collection<String>),因为这是类型擦除后的类型。

困惑?不奇怪。看看这个FAQ的大小。世界上大概有三个人理解Java泛型的全部含义。请考虑我最喜欢的来自JDK的声明:

Enum<T extends Enum<T>> 

(Theres在常见问题解答中也提到了这一点)。

+0

我正在做Thing通用因为另一种方法(我没有在我的例子中列出)。 – 2009-01-16 00:38:20

0

由于擦除而失败。你可以在这些阅读更多关于它Java Tutorials

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