泛型是java5的新特性,也是java中比较难掌握和理解的技术之一。泛型是用一对尖括号来表示的,下面就我对泛型的了解做一些简单的应用。
这段代码的第一句加了一个泛型<String>,也就是告诉编译器,这个集合里添加的元素全部是String类型的对象,如果不是则编译器会报错。可以通过反射的方法来强行传递传入非String类型的值,比如加入下面这一行代码: collection2.getClass().getMethod("add", Object.class).invoke(collection2, 18);所以collection2.add(1),ollection2.add(1L)这两句就不能通过编译。
定义类的时候ArrayList<E>,E可以称为是类型参数,或类型变量。应用的时候ArrayList<String>叫做参数化的类型,传入了具体的类型的值。
下面举例说明参数化类型与原始类型的兼容性:
1.Collection<String > c=new Vector();可以通过
2.Collection c=new Vector<String >();可以通过
3.Vector<String> v=new Vector<Object>();错误
4.Vector<String> v=new Vector<Object>();错误
结论:3,4编译失败表明参数化类型不考虑类型参数的继承性。
符号“?”在泛型中的应用。“?”是通配符,它可以作为引用变量引用各种变量 比如Collection<?>。限定通配符的上边界的定义:Vector<? extends Number>表明只能传递Number类型及其子类。限定通配符的下边界的定义:Vector<? super Integer>表明只能传入Integer及其父类。
泛型也可以应用到自己定义的方法,可以实行数组中元素的交换,比如下面这一段代码:
String[] str=new String[]{"111","222","333"};
swap(str);
public static <T> void swap(<T>[] a,int x,int y){
<T> temp=a[x];
a[y]=a[x];
a[x]=temp;
}
定义的时候比如ArrayList<E>,E可以称为是类型参数,或类型变量。应用的时候ArrayList<String>叫做参数化的类型。<E>的作用域,如果定义在类上,就作用于整个类,如果定义在方法上,作用于整个方法。静态方法不能用参数类型。类中有多个方法用泛型,应使用类级别的泛型,不使用方法级别的。
难点:用反射的方式获得泛型中具体传入的是什么类型。比如有一个方法如下
用传统的方法很难获得参数V1的泛型。那么通过以下一段代码即可获得
1代码是获得GenericTest类的applyVector方法的Method对象,2代码是通过applyMethod获得pplyVector方法中的参数列表数组(实际只有一个,那就是Vector),3代码是获得参数的参数化类型(就是Date),4.打印它的类型的类是Vector,5.打印它的实际类型参数是Date,如图。
首先集合中泛型的使用:
ArrayList<String> collection2=new ArrayList<String>();
collection2.add(1);
collection2.add(1L);
collection2.add("abc");
int j=(String)collection2.get(1);
所以,泛型是提供给编译器看的。如果有两个变量是参数化的类型,编译完后JVM不能知道参数的类型。编译生成的字节码会去除这些信息,所以运行后没这些信息了。
public static void applyVector(Vector<Date> v1){};
1. Method applyMethod=GenericTest.class.getMethod("applyVector", Vector.class);
2.Type[] types =applyMethod.getGenericParameterTypes();
3. ParameterizedType pType=(ParameterizedType)types[0];
4. System.out.println(pType.getRawType());
5. System.out.println(pType.getActualTypeArguments()[0]);