在日常编码过程中,我们定义一个List
,通常会同是为list
集合添加泛型,进行约束List<String>
,保证我们在list.add()
添加对象的时候,类型一致。
比如定义一个集合
public class ListDemo {
public static void main(String[] args) {
List<String> stringList = new ArrayList<>();
stringList.add("abc");
stringList.add(1);// 报错,无法通过编译
}
}
再创建一个新的list集合
List<Integer> integerList = new ArrayList<>();
使用getClass()
方法 获取stringList
和integerList
的类类型进行比较。
Class strListClass = stringList.getClass();
Class intListClass = integerList.getClass();
System.out.println(strListClass == intListClass);
打印结果:
true
也就是说类类型都是一致的。
编译之后的集合的泛型是去泛型化的。
java中集合的泛型,是防止错误输入,只在编译期有效,绕过编译就无效了。
那么我们只要绕过编译,就可以让这个泛型限制无效。
如何绕过编译呢?
反射的操作,都是编译后的操作,也就是运行时。
我们来验证一下,通过方法的反射来操作:
System.out.println(stringList);
try {
Method m = strListClass.getMethod("add",Object.class);
// 绕过编译去操作,也就绕过了泛型检测
m.invoke(stringList,1);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("--------------");
System.out.println(stringList);
打印结果:
[abc]
--------------
[abc, 1]
通过反射操作,将int
类型的数字1
添加到了 List<String> stringList
集合中。
这里还有一个需要注意的地方,虽然通过反射绕过泛型检测将数值添加了进去,但在遍历是会报错的。
for (String s : stringList) {
System.out.println(s);
}
这里会抛异常(类型转换异常):
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
文章链接:
Java 反射学习笔记(一)认识Class
java 反射学习笔记(二)方法的反射
java 反射学习笔记(三)通过反射机制,绕过编译时泛型检测
java 反射学习笔记(四)反射的基本操作和用法