一、泛型的好处
importjava.util.ArrayList;
public class GenericTest {
public static void main(String[]args) throws Exception{
//使用泛型限定集合类型为Integer
ArrayList<Integer> collection1 = newArrayList<Integer>();
//使用泛型限定集合类型是String
ArrayList<String> collection2 = newArrayList<String>();
//判断被泛型限定的两个集合是否指向同一份字节码
System.out.println(collection1.getClass()==collection2.getClass());
//通过反射向collection1中加入其它类型的对象
collection1.getClass().getMethod("add",Object.class).invoke(collection1,"test");
System.out.println(collection1.get(0));
}
}
以集合为例:
没有使用泛型任何对象都可以存储进同一个集合中。使用泛型集合,可以将一个集合中的元素指定为一个特定类型,集合中只能存储同一个类型的对象,这样对集合的操作更加安全和方便。
泛型的好处如下:
1、把运行时的异常转到了编译时期。
2、避免了程序员强制类型的转换
二、泛型的内部原理及应用
泛型是提供给Javac编译器使用的,通过限定集合中的输入类型,可以阻止源程序中的非法输入,在运行的过程中,泛型信息会被擦除。通过反射方法跳过编译器,就会使泛型无效。编译器不允许创建泛型变量的数组。即在创建数组实例时,数组的元素不能使用参数化的类型。
参数化类型与原始类型的兼容性,考虑到与以前代码的兼容性,如下代码可以通过编译。
Collection<String>v =new Vector();
参数化类型不考虑类型参数的继承关系,以下两种写法都是错误的:
Vector<String> v =new Vector<Object>();
Vector<Object> v =new Vector<String>();
泛型使用?号作为通配符,如果我们定义变量或者方法时不确定类型是什么,就可以使用?通配符来表示。
通配符的扩展
限定通配符的上边届
//限定为:Number或Number的子类
正确:Vector<? extendsNumber>x = new Vector<Integer>();
错误:Vector<? extendsNumber>x = new Vector<String>();String不是Number的子类。
正确:Vector<? super Integer>x= new Vector<Number>();必须是Integer的父类,往下最低是Integer本身。
错误:Vector<? super Integer>x= new Vector<Byte>();//Byte与Integer是平级,和Integer没有关系。
泛型和Map集合的一个综合例子:
public class MapTest2 {
public static void main(String[] args){
Map<String,String> map = new HashMap<String,String>();
//添加元素
map.put("1","Kevin");
map.put("2","Smart");
map.put("3","T1");
//将Map中的键转换为Set集合
Set<Map.Entry<String, String>> keySet =map.entrySet();
//通过Set集合中的迭代器取出Map中的键值对
for(Iterator<Map.Entry<String, String>>it=keySet.iterator();it.hasNext();)
{
Map.Entry<String, String> entry = it.next();
//取得键
System.out.println(entry.getKey());
//取得value值
System.out.println(entry.getValue());
}
}
}
三、自定义泛型
如果类的实例对象中的多处都要用到同一个泛型参数。即这些地方引用的泛型类型要保持同一个实际类型时,这时候就要采用泛型类型的方式进行定义,也就是类级别的泛型,语法格式如下:
publicclass Generic <E> {
private T fleld;
public void save(T obj){}
public T getId(int id){}
}
类级别的泛型是根据引用该类名时指定的类型信息来参数化类型变量的,例如,如下两种方式都可以:
Generic<User> dao = null;
Generic< User > dao =new Generic<User>();
四、通过反射获得泛型的实际参数
通过参数化类型的变量是无法得到实际类型参数的,只能通过将它作为参数的方法才能获取到实际类型参数。
public class Test {
public static void main(String[] args) throws Exception, SecurityException {
Method applyMethod = Test.class.getMethod("testVector", Vector.class);
// 获取方法的泛型参数类型,返回的是个数组
Type[] types = applyMethod.getGenericParameterTypes();
// ParameterizedType参数化类型
ParameterizedType pType = (ParameterizedType) types[0];
// 获取原型
System.out.println(pType.getRawType());
// 获取参数化类型
System.out.println(pType.getActualTypeArguments()[0]);
}
public static void testVector(Vector<Date> v1) {
}
}