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”);}
是的,我称之为忽略而不是欺骗编译器。编译器知道发生了什么。