考虑一下代码:
public class GenericsConfusion {
public static <T> Class<T> get(Class<T> clazz) {
Map<Class, Class> map = new HashMap<Class, Class>();
map.put(Integer.class, String.class);
return map.get(clazz);
}
public static void main(String[] args) {
Class<Integer> clazz = get(Integer.class);
System.out.println(clazz);
}
}
它编译并运行完美。我们的想法是在get方法中返回与输入类具有相同类型参数的类。但由于地图的存在,它被打破了。
是的,我知道在运行时会删除类型参数信息,因此如果没有类型参数,则此代码完全有效。另外我知道我可以通过指定Map<Class<T>, Class<T>>
来修复它但事实是在方法签名中我有类型参数,它们在编译时没有帮助我。
这是对某些概念的误用吗?
或者它是Java泛型的缺点?
或者它完全可以,我误解了类型参数的想法?
答案 0 :(得分:8)
原始类型,例如Class
或Map
(与Class<...>
或Map<..., ...>
相对),规避了类型检查仿制药。你甚至可以这样写:
final Class<Integer> whoops = (Class) String.class;
这是类型系统中一个令人遗憾的弱点。它最初包含在Java 5(引入泛型)中,与先前版本中编写的代码兼容。
在大多数情况下,您可以通过避免使用原始类型来避免这种弱点。你的编译器应该警告你。
不幸的是,在各种情况下,原始类型基本上是不可避免的(由于.getClass()
的特殊输入;由于我们只能编写(例如)Map.class
而不是{{ 1}}(或Map<String, String>.class
);由于擦除和反射等原因);但幸运的是,正如你所指出的,你的情况似乎并不是其中之一。
答案 1 :(得分:0)
我猜你要从地图上归还一些东西?
目前,理论上你可以在地图中存储除Class<T>
之外的其他内容,例如Class<Y>
,但不是来自此代码,而是泄漏引用等。要将地图中的内容作为{{1}返回您必须强制地图仅存储Class<T>
而不存储任何其他内容。
目前,它可以在我相信的同时存储Class<T>
和Class<T>
。