版权声明:欢迎转载,但请注明出处! https://blog.csdn.net/DavidHuang2017/article/details/85332855
1.泛型类型安全检查
泛型的生存期为编译阶段,编译后生成字节码形式的Class文件,泛型信息被擦除,专业术语叫做类型擦除。所以在编译阶段,编译器会进行泛型类型安全检查,保证泛型类型匹配。
List<String> list = new ArrayList<>();
list.add("aaa");
list.add(100);//无法编译通过
因为编译时会进行泛型类型安全检查,上面最后一行代码无法编译通过。
来看一下add方法的源码:
public class ArrayList<E>{
public boolean add(E e) {
//...
}
}
泛型类型参数E确定为String后,在编译时,上述代码相当于:
public class ArrayList<String>{
public boolean add(String e) {
//...
}
}
在编译代码list.add(100);
时,实参类型与形参类型不匹配,所以无法编译通过。这就是泛型类型安全检查,保证了代码类型匹配时的安全性。
2.泛型类型擦除
泛型的生存期为编译阶段,编译后生成字节码形式的Class文件,泛型信息被擦除,专业术语叫做类型擦除。
泛型时java1.5才引入的,因为泛型类型擦除,使得泛型代码能与之前的代码兼容。
List<String> l1 = new ArrayList<>();
List<Integer> l2 = new ArrayList<>();
System.out.println(l1.getClass() == l2.getClass());
因为泛型类型擦除,,List<String>
和List<Integer>
在jvm中的Class对象都是List.class
;所以上面代码的输出为true。
泛型转译:<T>
中T转译成Object,而类似<T extends String>
转译成类型上限。
3.通过反射逃避泛型安全检查
因为泛型类型擦除的存在,我们可以借助反射的手段逃避泛型安全检查,使得第一节中往List中加入Integer类型元素能实现。
/*
* 通过反射逃避泛型检查
* 例如:有一个String泛型的List,怎样能向这个List中添加一个Integer类型的值?
*/
public class Demo {
public static void main(String[] args) throws Exception{
ArrayList<String> strList = new ArrayList<>();
strList.add("aaa");
strList.add("bbb");
// strList.add(100);//无法编译通过,因为泛型类型检查
//获取ArrayList的Class对象,反向调用add()方法,添加元素
Class listClass = strList.getClass(); //得到 strList 对象的字节码 对象
//获取add()方法
Method m = listClass.getMethod("add", Object.class);
//调用add()方法
m.invoke(strList, 100);
//遍历集合
for(Object obj : strList){
System.out.println(obj);
}
}
运行结果:
aaa
bbb
100