本帖最后由 笑脸迷人 于 2014-8-30 19:26 编辑
1、泛型原理:
泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,
编译器编译带类型说明的集合时会去掉"类型"信息,使程序运行效率不受影响,(去类型化)
所以:对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样。代码1
- ArrayList<String> collection1=new ArrayList<>();
- ArrayList<String> collection2=new ArrayList<>();
- System.out.println(collection1.getClass()==collection2.getClass());
复制代码
由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其他类型的数据
例如,使用反射得到集合,再调用其add方法即可,如下
代码2
- Method methodAdd=collection2.getClass().getMethod("add", Object.class);
复制代码 2、参数化类型ArrayList<E>与原始类型ArrayList的可兼容
对以下做法,编译器报告警告,但不会报错误(运行也可以)
Collection<String> c=new Vector();
Collection c=new Vector<String>();
其不报错的原理就是泛型的去类型化造成的,那么我们可以重新思考使用反射技术往参数化类型ArrayList<Integer>中添加非Integer的数据了:是不是可以使用另外的原始类型ArrayList的引用变量指向这个参数化类型ArrayList<Integer>,使用原始类型ArrayList的引用变量调用add方法往集合里面添加数据呢?代码测试如下:
代码3- ArrayList<Integer> a=new ArrayList<Integer>();
- ArrayList a2=a;//使用原始类型ArrayList的引用变量指向这个参数化类型ArrayList<Integer>
- a.add(1);
- a2.add("abc");//添加String类型
- System.out.println(a.get(0));//1
- System.out.println(a.get(1));//abc
- System.out.println(a);//[1, abc]
复制代码
其实代码中ArrayList<Integer> v=new ArrayList<Integer>(); 的右边Integer也可以省略~,
简而言之,给集合添加的泛型只需要看左边就好~
这样一来感觉泛型的出现还是不好解决往集合里添加指定类型元素过滤的功能,万一不小心又有一个无泛型的集合引用指向了他呢?
3、疑问:先看错误代码4
- ArrayList<String> v=new ArrayList<String>();
- ArrayList v2=v;//使用原始类型ArrayList的引用变量指向这个参数化类型ArrayList<Integer>
- v2.add(1);
- v.add("abc");//添加String类型
- System.out.println(v.get(0));//<font color="#ff0000">类型转换异常</font>!!!
- System.out.println(v.get(1))
- System.out.println(v);
复制代码 异常分析:v.get()这个方法的返回值是一个String类型的变量(泛型的限定),但是v.get(0)是将集合中角标为0的元素返回,这个元素是Integer类型的,所以会报错。
但请看代码3中的 System.out.println(a.get(1));这句话却是没有报异常,按理来说,a被泛型限定为Integer类型的变量,返回的元素却是String类型的,这也应该报异常啊,为什么?
|
|