Java泛型进阶

版权声明:欢迎转载,但请注明出处! 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

参考博客:https://blog.csdn.net/briblue/article/details/76736356

猜你喜欢

转载自blog.csdn.net/DavidHuang2017/article/details/85332855