java 反射学习笔记(三)通过反射机制,绕过编译时泛型检测

2019-11-17  本文已影响0人  夕决_

在日常编码过程中,我们定义一个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()方法 获取stringListintegerList的类类型进行比较。

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 反射学习笔记(四)反射的基本操作和用法

上一篇 下一篇

猜你喜欢

热点阅读