泛型擦除(Generic erase)(内含教学视频+源代码)
教学视频+源代码下载链接地址:
https://download.csdn.net/download/weixin_46411355/87473560
源代码中使用的泛型,在经过编辑后,代码中就看不到泛型,也就是所谓的泛型擦除
泛型擦除不是泛型丢失了,而是在编译后的字节码文件中使用单独的标识来存储泛型了。
为什么会出现泛型擦除,主要是为了编译器的兼容性。
因为在jdk5之前是没有泛型的,jdk5之后出现了泛型。
为了编译器的兼容性,在编辑代码的时候就将泛型擦除了,这样就和之前没有泛型的时候编译一样了。
Java代码编译前会进行代码校验。代码能够通过校验,说明代码语法是没有问题的。所以编译的时候可以擦除泛型。
比如:
ArrayList<String> list = new ArrayList<>();
list.add("java");
ist.add("hello");
以上代码可以校验通过,说明集合中的元素一定是符合泛型的类型的,所以此时编译擦除泛型不受影响
ArrayList list = new ArrayList();
list.add("java");
list.add("hello");
import java.util.ArrayList;
import java.util.Arrays;
/**
* 泛型擦除(Generic erase):
*
* 源代码中使用的泛型,在经过编辑后,代码中就看不到泛型,也就是所谓的泛型擦除
*
* 泛型擦除不是泛型丢失了,而是在编译后的字节码文件中使用单独的标识来存储泛型了。
*
* 为什么会出现泛型擦除,主要是为了编译器的兼容性。
* 因为在jdk5之前是没有泛型的,jdk5之后出现了泛型。
* 为了编译器的兼容性,在编辑代码的时候就将泛型擦除了,这样就和之前没有泛型的时候编译一样了。
* Java代码编译前会进行代码校验。代码能够通过校验,说明代码语法是没有问题的。所以编译的时候可以擦除泛型。
* 比如:
* ArrayList<String> list = new ArrayList<>();
* list.add("java");
* list.add("hello");
* 以上代码可以校验通过,说明集合中的元素一定是符合泛型的类型的,所以此时编译擦除泛型不受影响
* ArrayList list = new ArrayList();
* * list.add("java");
* * list.add("hello");
*
*
*/
public class GenericErasure {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("java");
list.add("hello");
System.out.println(list);
}
}
找到它的字节码文件
打开反编译工具XJad
将字节码文件拖拽进反编译工具XJad中
通过GenericErasure.class字节码文件被XJad反编译工具反编译后,就没有泛型了,说明泛型被擦除了,但是在字节码的其它信息里存的有。
鼠标右击这个GenericErasure.class字节码文件,打开它所在的目录
在地址栏上输入cmd,然后按回车
输入javap -v GenericErasure.class
javap -v
: class字节码文件中除了包-c参数包含的内容外,还会输出行号、局部变量表信息、常量池等信息;
说明:在字节码文件中 本地变量类型表格LocalVariableTypeTable中 是存的有泛型的类型。泛型的类型是在的,没有丢,只是擦除了。