对generics类的非generics引用会导致非generics返回类型
我有一个遗留类,该类本身不是通用的,但其方法之一返回类型使用generics:
public class Thing { public Collection getStuff() { ... } }
getStuff()
使用generics返回字符串集合。 因此,我可以迭代getStuff()
并且不需要将元素转换为String
:
Thing t = new Thing(); for (String s: t.getStuff()) // valid { ... }
但是,如果我将Thing
本身更改为通用,但保持其他所有内容相同:
public class Thing { public Collection getStuff() { ... } }
然后继续使用对Thing
的非generics引用, getStuff()
不再返回Collection
,而是返回一个非类型的Collection
。 因此客户端代码不编译:
Thing t = new Thing(); for (String s: t.getStuff()) // compiler complains that Object can't be cast to String { ... }
为什么是这样? 解决方法有哪些?
我的猜测是,通过使用对generics类的非generics引用,Java会关闭整个类的所有generics。 这很痛苦,因为现在我通过使Thing成为通用来破坏我的客户端代码。
编辑:我正在为上面的示例代码中未列出的另一种方法制作Thinggenerics。 我的问题是关于为什么不能做到这一点的教育。
好的,拿两个,我误解了你的问题。
当您使用deling Thing
(这称为原始类型 )而不是Thing>
( 参数化类型 )时,Java编译器将删除所有generics参数,甚至thogh(如您的情况),该方法的generics类型与此无关类的generics类型。
来自(优秀) Javagenerics常见问题解答 :
我可以使用任何其他类型的原始类型吗?
原始类型的方法或构造函数具有在类型擦除之后将具有的签名。
这个看似无害且不引人注意的句子描述了有问题的行为。 您使用Thing
作为原始类型,因此返回类型是Collection
(而不是Collection
),因为这是类型擦除后的类型。
困惑? 不奇怪。 只需看看常见问题解答的大小。 地球上可能有大约三个人理解Javagenerics的全部含义。 只考虑我最喜欢的JDK声明:
Enum>
(这也是FAQ中对此的解释)。
它因擦除而失败。 您可以在这些Java教程中阅读有关它的更多信息
我认为这是完全正常的。 在我看来,使用Thing t = new Thing(); 对于通用启用类是完全错误的。 当编译器看到用作没有类型参数的类的generics类时,它认为它必须擦除该类中的所有generics类型。 这就是你如何在新的java编译器和编译器中编译旧代码而不使用generics,让旧代码使用通用的启用类(例如java.util.ArrayList)而没有任何问题。 (这就是java不需要像C#那样分离System.Collection.Generic.List和System.Collection.List)。 你可以运行Thing t = new Thing();
在其上添加一个简单的类型参数, Thing
,java编译器只需要确保你有意识地使用java通用。 我永远不能责怪Java的强大向后兼容性。
我知道我有点迟了:D