泛型总结
import java.util.ArrayList; import java.util.List; import java.util.Vector; //为什么要使用泛型 class Student{ private int studentnum; public Student(int number){ studentnum=number; } public String toString(){ return " "+this.studentnum; } } public class GenericMethodDemo1{ public static void main(String[] args){ Vector v=new Vector(); Student s1=new Student(1); Student s2=new Student(2); Student s3=new Student(3); Student s4=new Student(4); Student s5=new Student(5); Student s6=new Student(6); Integer t=new Integer(10); v.add(s1); v.add(s2); v.add(s3); v.add(s4); v.add(s5); v.add(s6); v.add(t); for(int i=0;i<v.size();i++){ Student s=(Student) v.get(i); System.out.print(s.toString()+" "); } } }
/*(1)上述代码虽然编译通过,但是运行时却出现了异常————ClassCastException。这主要是遍历集合对象v的最后
* 一个对象时,由于该对象t是一个Integer对象而不是Student对象,所以在运行Student s=(Student) v.get(i);
* 代码时会出错。
* (2)对于上述代码存在安全隐患,即强制转换类型时会出现错误,编译器是不会提示出现错误的,但是在运行时却会
* 出现异常。因此需要使用泛型,用来限制向对象集合中添加对象的类型,如果添加的类型不是指定的泛型类型,就会出现
* 编译时错误。例:Vector<Student> v=new Vector();这句代码限制了集合v中的对象只能是Student对象
* */
*******************************************************************************************************************************
*******************************************************************************************************************************
泛型的一些特性
* 1.参数化类型与原始类型的兼容
* 也就是说指定的泛型类型可以放在等号左边也可以放在等号右边(编译器只会警告,但是不会报错)
* 例:
* Vector<String> v=new Vector();
* Vector v=new Vector<String>();
* 2.参数化类型无继承性
* Vector<String> v=new Vector();
* Vector<Object> v1=v;
* 有些程序员认为由于String类型是Object类型的子类,所以String类型的Vector对象v可以赋值给Object类型的
* Vector对象v1。
* v1.add(new Object());
* String s=v.get(0);
* 在上述代码中,首先v1对象中添加一个Object类型对象成员,接着由于v1与v都指向同一个对象,所以可以通过v对象
* 获取添加到v1对象中的成员。这时就会出现错误,因为v对象中的成员不再是String类型。所以代码Vector<Object> v1=v;
* 是错误的。
* 3.泛型的“去类型”的特性
* 所谓“去类型”,就是指泛型中的类型只是提供给编译器使用,当程序编译成功后就会去掉“类型”信息。如下面的代码:
import java.util.ArrayList; public class GenericMethodDemo2 { public static void main(String[] args) { ArrayList<String> array1=new ArrayList<String>(); array1.add("hujingwei"); ArrayList<Integer> array2=new ArrayList<Integer>(); array2.add(20); System.out.println("array1与array2是否指向同一份字节码?"+(array1.getClass()==array2.getClass())); } }
*
*
* 4.利用反射绕过泛型的类型限制
* 由于编译器生成的字节码去掉泛型的类型信息,所以只要跳过编译器,还是可以给通过泛型限制的类型集合加入
* 其他数据类型。如下面的代码:
import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; public class GenericMethodDemo3 { public static void main(String[] args) throws IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException,
NoSuchMethodException { ArrayList<Integer> array1=new ArrayList<Integer>(); array1.add(12); array1.add(34); array1.getClass().getMethod("add", Object.class).invoke(array1, "abc"); System.out.println("第一个元素为:"+array1.get(0)); System.out.println("第二个元素为:"+array1.get(1)); System.out.println("第三个元素为:"+array1.get(2)); } } import java.util.Vector; 泛型通配符 //<?>类型的通配符 public class GenericMethodDemo4 { public static void main(String[] args) { Vector<Integer> v=new Vector<Integer>(); v.add(2); v.add(5); Vector<Object> v1=new Vector<Object>(); v1.add("aa"); v1.add(2.3); randomMeth(v); randomMeth(v1); } private static void randomMeth(Vector<?> vector) { System.out.println("输出"+vector+"各个成员-------------"); for(Object obj:vector){ System.out.println(obj); } System.out.println("对象的大小"+vector.size()); } } /*在randomMeth方法中,通过?标识实现接受任何类型参数的方法,即在具体调用具体方法时,传入的对象 * 可以是任意类型。虽然可以接受任意类型,但是具体接受什么类型只是在具体调用该方法时才能确定。因此在 * 该方法中添加类型成员vector.add("1");时,就会出现编译错误。可是如果调用与参数无关的方法时vector.size(), * 则不会报错。 * */ import java.util.ArrayList; import java.util.List; //<? extends U> <? super U> public class GenericMethodDemo5 { public static void main(String[] args) { Number num1=new Integer(1); Number num2=new Double(1.23); List<Number> listNums=new ArrayList<Number>(); listNums.add(1); listNums.add(1.23); List<Integer> listInteger=new ArrayList<Integer>(); List<Number> listNums1=new ArrayList<Number>(); List<? extends Number> listNums2=listInteger; List<? super Integer> listNums3=listInteger; listNums3.add(7); listNums3.add(null); } } /*对象num1和num2的定义代码,子类(Integer,Double)可以自动转换成其父类(Number)。同理,ArrayList<Number> * 泛型也可以自动转换成List<Number>泛型,因为List是ArrayList类的父类。 * List<Integer>类型的对象listInteger,之所以不能赋给List<Number>类型的对象listNums1,是因为泛型参数类型无 * 继承性。因此,虽然Integer是Number的子类,但是充当放行参数时,则不能实现转换。 * 为了解决泛型参数类型无继承性,出现了extends和super标识符。List<? extends Number> listNums2;表示该对象可以被 *Number类型的任何子类对象(List<Integer>)赋值。List<? super Integer>表示该对象可以被Integer类型的父类对象赋值。 * * */