Java 泛型混淆:欺骗编译器
考虑一个代码:Java 泛型混淆:欺骗编译器,java,generics,Java,Generics,考虑一个代码: 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.
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(类clazz){
Map Map=newhashmap();
map.put(Integer.class、String.class);
返回map.get(clazz);
}
公共静态void main(字符串[]args){
Class clazz=get(Integer.Class);
系统输出打印(clazz);
}
}
它可以完美地编译和运行。其思想是在get方法中返回与输入类具有相同类型参数的类。但由于地图的存在,它被破坏了。
是的,我知道在运行时类型参数信息会被删除,所以如果没有类型参数,这段代码是完全有效的。我也知道我可以通过指定Map
来修复它,但事实是在方法签名中我有类型参数,它们在编译时对我没有帮助
这是对某些概念的误用吗
或者这是Java泛型的一个缺点
还是完全没问题,我误解了类型参数的概念?我猜你会从地图上返回一些东西 目前,从理论上讲,您可以在地图中存储
类
以外的内容,例如类
,尽管不是来自此代码,而是泄漏的引用等。要从地图中返回内容作为类
,您必须强制地图仅存储类
,而不存储其他内容
目前,我相信它可以同时存储类
和类
。原始类型,如类
或映射
(与类
或映射
相反),可以绕过泛型的类型检查。你甚至可以这样写:
final Class<Integer> whoops = (Class) String.class;
final Class whoops=(Class)String.Class;
这是打字系统中一个不幸的弱点。它最初包含在Java5(它引入了泛型)中,以便与以前版本下编写的代码兼容
在大多数情况下,您可以通过避免使用原始类型来避免这种缺点。您的编译器应该警告您这些错误
不幸的是,在许多情况下,原始类型基本上是不可避免的(由于
.getClass()
的特殊类型;由于我们只能编写(例如)Map.class
而不能编写Map.class
(或Map.class
);由于擦除和反射等);但令人高兴的是,正如您所注意到的,您的情况似乎并非如此。这是Java类型系统中的一个弱点,它是在向语言中添加类型参数时出现的,但在不禁止原始类型以实现向后兼容性的情况下,javac确实会警告此代码中未经检查或不安全的操作。尽管它编译并运行正确,但代码中有一个警告:unchecked赋值:'java.lang.Class'到'java.lang.Class'的值小于。。。(Ctrl+F1)仅限JDK 5.0。表示编译器发出未检查警告的位置,例如:void f(HashMap map){map.put(“key”,“value”);}
是的,我称之为忽略而不是欺骗编译器。编译器知道发生了什么。