编译器是否在编译时删除了泛型

Vic*_*tor 9 java generics

在本教程中反思它指出:

[...]因为泛型是通过类型擦除实现的,它在编译期间删除了有关泛型类型的所有信息

我的知识是使用泛型,以便在编译时编译器可以检查类型安全性.即快速接近失败.但链接提到类型擦除会在编译期间删除通用信息.

das*_*ght 11

您引用的语句是正确的:编译器在编译过程中在内部使用泛型类型信息,在处理源时生成与类型相关的错误.然后,一旦验证完成,编译器就会生成类型擦除的字节代码,所有对泛型类型的引用都将替换为它们各自的类型擦除.

当您通过反射查看类型时,这一事实变得明显:所有接口,类和函数都变为非泛型,所有类型都绑定到泛型类型参数,并根据源中指定的泛型类型约束替换为非泛型类型码.虽然反射API确实具有在运行时访问与泛型*相关的一些信息的规定,但是当您通过反射访问类时,虚拟机无法检查完全兼容的通用类型.

例如,如果您创建类型的类成员List<String>并尝试设置List<Integer>它,编译器将抱怨.但是,如果你试图通过反射来做同样的事情,编译器就不会发现,并且代码将在运行时以与没有泛型的方式相同的方式失败:

class Test {
    private List<String> myList;
    public void setList(List<String> list) {
        myList = list;
    }
    public void showLengths() {
        for (String s : myList) {
             System.out.println(s.length());
        }
    }
}

...

List<Integer> doesNotWork = new ArrayList<Integer>();
doesNotWork.add(1);
doesNotWork.add(2);
doesNotWork.add(3);
Test tst = new Test();
tst.setList(doesNotWork); // <<== Will not compile
Method setList = Test.class.getMethod("setList", List.class);
setList.invoke(tst, doesNotWork); // <<== This will work;
tst.showLengths(); // <<== However, this will produce a class cast exception
Run Code Online (Sandbox Code Playgroud)

在ideone上演示.


*有关在运行时获取与泛型类型相关的信息的详细信息,请参阅此答案.

  • -1; 这种解释具有误导性.您可以通过使用反射来查看一些泛型类型约束.例如,如果你调用`Test.class.getDeclaredField("myList").getGenericType()`,你将获得`List <String>`,而不是`List`.[演示中的演示](http://ideone.com/y6wPHG). (3认同)