泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,编译器编译带类型说明的集合进会去掉“类型”信息,使程序运行效率不受影响。
由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合虽加入其它类型的数据。
所以我们可以用反射为泛型集合添加其他类型的数据。
例1:
ArrayList<Integer> arrayList = new ArrayList<Integer>(); arrayList .add(10); arrayList .add(20); arrayList .getClass().getMethod("add",Object.class).invoke(arrayList ,"hbase"); System.out.println(arrayList .get(2));//虽然索引为2的位置存的是String类型,但编译时编译器会认为arrayList .get(2)返回的时是Integer类型,但在运行取值时取的仍是 //String类型
输出:hbase
例2:
ArrayList<String> arrayList = new ArrayList<String>(); arrayList1.add("hadopp"); arrayList1.add("hive"); arrayList1.getClass().getMethod("add",Object.class).invoke(arrayList1,25); System.out.println(arrayList1.get(2));//虽然索引为2的位置存的是Integer类型,但编译时编译器会认为arrayList .get(2)返回的时是String类型,但在运行取值时取的仍 //Integer类型
报错!! Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String at com.mobin.generic.GenericTest.main(GenericTest.java:20)
报错代码:System.out.println(arrayList1.get(2));
Integer不能转成String,但例1为会又不报ClassCastException异常呢?(大家也可以先想想原因是什么再看下面的分析)
下面分析下原因:
出现ClassCastException这个异常可以断定的是类型的转换错误。
原因就在Syststem.out.println这条语句,
上图是println()的所有重载方法,除了bool,char,char[],double,float,int,String,long类型外,当传入的参数是其他类型时被会被当作是Object从而调用println(Object)方法。
在例1中由于arrayList1.get(2)返回的是Integer所以调用的是println(Object)方法,验证:把鼠标放到println方法上即可.
好,我们再进入println(Object x)的源码去看看
参数都被自动的转成了String类型!!!
相当于Object x = arrayList.get(2); //所有对象都属于Object
String s = String.valueOf(x);
所以不会报错。
再看第二段代码的println调用的是println(String x);
同样进入源码去看看:
相当于String x = arrayList.get(2); //这里运行时arrayList.get(2)所得的值的类型是Integer,又相当于String x = Integer;所以才报错