写ArrayList源码学习笔记(3)的时候发现了ArrayList因为泛型擦除而导致元素存储使用的是Object数组。
然后又了解到泛型出现之后存在类型转换的问题,所以研究了java泛型的逆变、协变&不变。
后来又想到几个问题如下:
(1)java为什么要做类型擦除?
(2)java是如何做的类型擦除?
(3)类型擦除之后,是怎么在后续使用过程中识别类型的?
于是搜到了这两篇文章解决了疑惑:Java 泛型,你了解类型擦除吗? 知乎问答
(1)了解到的原因是为了做兼容,引入泛型之后不会对当前的逻辑造成影响,只需要对泛型进行特殊扩展即可。
(2)java代码编译后,只保留了其基础类型,泛型类型以另外的字段记录在class文件中。
(3)因为记录在class文件里,总有办法能读取出来。
意外收获:虽然泛型能控制add参数的类型,但是反射依然是能将不同类型的元素加入到list里的,来自第一篇文章的一个例子
public class ToolTest { public static void main(String[] args) { List<Integer> ls = new ArrayList<>(); ls.add(23); // ls.add("text"); try { Method method = ls.getClass().getDeclaredMethod("add",Object.class); method.invoke(ls,"test"); method.invoke(ls,42.9f); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } for ( Object o: ls){ System.out.println(o); } } }打印结果是:
23 test 42.9