泛型混淆:欺骗编译器

Mia*_*ach 9 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.get(clazz);
    }

    public static void main(String[] args) {
        Class<Integer> clazz = get(Integer.class);
        System.out.println(clazz);
    }
}
Run Code Online (Sandbox Code Playgroud)

它编译和运行完美.我们的想法是在get方法中返回与输入类具有相同类型参数的类.但由于地图的存在,它被打破了.是的,我知道在运行时会删除类型参数信息,因此如果没有类型参数,则此代码完全有效.另外我知道我可以通过指定修复它Map<Class<T>, Class<T>>但事实是在方法签名中我有类型参数,并且它们在编译时没有帮助我.

这是滥用某些概念吗?

或者它是Java泛型的缺点?

或者它完全可以,我误解了类型参数的想法?

rua*_*akh 8

原始类型,如ClassMap(相对于Class<...>Map<..., ...>),绕过泛型的类型检查.你甚至可以写这样的东西:

final Class<Integer> whoops = (Class) String.class;
Run Code Online (Sandbox Code Playgroud)

这是类型系统中一个令人遗憾的弱点.它最初包含在Java 5(引入泛型)中,以便与先前版本中编写的代码兼容.

在大多数情况下,您可以通过避免使用原始类型来避免这种弱点.您的编译器应该警告您.

不幸的是,在各种情况下,原始类型基本上是不可避免的(由于特殊的类型.getClass();由于我们只能写(例如)Map.class而不能Map<String, String>.class(或Map.<String, String>class);由于擦除和反射等原因;); 但幸运的是,正如你所指出的,你的情况似乎并不是其中之一.