编译器在编译时删除泛型 [英] Are generics removed by the compiler at compile time

查看:117
本文介绍了编译器在编译时删除泛型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

思考的本教程中,它指出:因为泛型是通过类型擦除来实现的,该类型擦除在编译过程中删除了有关泛型类型的所有信息。
$ b


/ blockquote>

我的知识是使用泛型,因此在编译时编译器可以检查类型安全性。即失败的快速方法。
但是链接提到类型删除在编译期间删除了一般信息。

解决方案

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



这个事实在通过反射来查看类型:所有接口,类和函数都变得非泛型,所有与泛型类型参数绑定的类型都被替换为基于源代码中指定的泛型类型约束的非泛型类型。尽管反射API在运行时提供了访问与泛型相关的一些信息的规定,但当您通过反射访问类时,虚拟机无法检查确切的泛型类型是否兼容。



例如,如果您创建类型为 List< String> 的类成员,并尝试设置列出< Integer> ,编译器会报错。但是,如果您尝试通过反射来做同样的事情,那么编译器不会发现,并且代码在运行时会失败,就像没有泛型一样:

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

...

List< Integer> doNotWork = new ArrayList< Integer>();
doesNotWork.add(1);
doesNotWork.add(2);
doesNotWork.add(3);
Test tst = new Test();
tst.setList(doesNotWork); //<< ==不会编译
方法setList = Test.class.getMethod(setList,List.class);
setList.invoke(tst,doesNotWork); //<< ==这会起作用;
tst.showLengths(); //<< ==然而,这将产生类别转换异常

关于ideone的演示。






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

In this tutorial on reflection it states:

[...] because generics are implemented via type erasure which removes all information regarding generic types during compilation

My knowledge was that generics are used so that at compile time the compiler can check for type safety. i.e fail fast approach. But the link mentions that type erasure removes generic information during compilation.

解决方案

The statement that you quoted is correct: the compiler uses the generic type information internally during the process of compilation, generating type-related errors as it processes the sources. Then, once the validation is done, the compiler generates type-erased byte code, with all references to generic types replaced with their respective type erasure.

This fact becomes evident when you look at the types through reflection: all interfaces, classes, and functions become non-generic, with all types tied to generic type parameters replaced with a non-generic type based on the generic type constraints specified in the source code. Although reflection API does have provisions for accessing some of the information related to generics* at runtime, the virtual machine is unable to check the exact generic type for compatibility when you access your classes through reflection.

For example, if you make a class member of type List<String> and try setting a List<Integer> into it, the compiler is going to complain. If you try to do the same through reflection, however, the compiler is not going to find out, and the code will fail at run-time in the same way that it would without generics:

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

Demo on ideone.


* See this answer for details on getting information related to generic types at runtime.

这篇关于编译器在编译时删除泛型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆