----------android培训、java培训、期待与您交流!----------
1.泛型概述
泛型是JDK1.5版本以后出现的新特性,用于解决安全问题,是一个类型安全机制。
类的后面跟着<E>这样的标识,如Vector<E>、ArrayList<E>等,这个<E>标识就代表泛型。
其本质就是实现参数化类型,也就是说所操作的数据类型被指定为一个参数。
1 、将运行时期出现的问题 ClassCastException 转移到了编译时期,方便程序员解决,让运行时期问题减少。
2 、避免了强制转换麻烦。
import java.util.*;
class GenericDemo{
public static void main(String[] args){
//定义了一个String类型的数组列表
ArrayList<String> al = new ArrayList<String>();
al.add("abc002");
al.add("abc013");
al.add("abc256");
al.add("abc028");
//al.add(4);//al.add(new Integer(5));
//迭代器要使用泛型
Iterator<String> it = al.iterator();
while(it.hasNext()){
String s = it.next();
System.out.println(s);
}
}
}
/*
结果
abc002
abc013
abc256
abc028
*/
2.泛型通配符:
? 泛型的通配符,也叫占位符
import java.util.ArrayList;
import java.util.Collection;
import java.util.Vector;
public class GenerticTest {
public static void main(String[] args) throws Exception{
ArrayList<String> al=new ArrayList<String>();
printCollection1(al);//正确
// printCollection(al);// 错误,无法将ArrayList<String>与Collection<Object>进行匹配
}
//需求:一个能将装着不同类型元素的集合打印出来
public static void printCollection(Collection<Object> collection){
collection.add("abc");//不会报错,因为String为Obeject的子类
for(Object obj:collection){
System.out.println(obj);
}
}
public static void printCollection1(Collection<?> collection){
// collection.add("abc");//报错,用通配符后无法使用与类型有关的特有方法
collection.size();
for(Object obj:collection){
System.out.println(obj);
}
}
}
3.泛型限定:
上限:<? extends E> 可以接受E类型或者E的子类型。
下限:<? super E> 可以接收E类型或者E的父类型
4.自定义泛型方法:
类型推断:如上例子,自定义泛型类型T后,JVM会根据调用时传入的实际参数类型,将T推断为各个实例参数的最大交集。
类型范围:只有引用数据类型才能作为泛型方法的实际参数类型
例子如下:
package it.cast.day2;
import java.util.Arrays;
//自定义泛型方法
public class GenerticTest1 {
public static void main(String[] args){
String[] stra=new String[]{"s","g","ag","ok"};
int[] inta={1,3,7,68,6};
swap(stra,1,2);
// swap(inta,0,2);//此处报错,因为只有引用数据类型才能作为泛型方法的实际参数类型(T)。
System.out.println(Arrays.asList(stra));
}
public static <T>void swap(T[] t,int a,int b){//自定义泛型方法
T temp=t[a];
t[a]=t[b];
t[b]=temp;
}
}
注:
1:使用范围:普通方法、构造方法和静态方法中都可以使用泛型。
2.也可以用类型变量表示异常,成为参数化的异常,可以用于方法的throw列表中,但是不能用于catch子句中。
3.在反省中可以同时有多个类型参数,在定义他们的<>中用逗号分开,例如:
public static <K,V> getValue(K key){return map.get(Key k)}
5.自定义泛型类型:
如果类的对象中的多出都要用到同一个泛型参数,即这些地方引用的泛型类型要保持同一实际类型时,这个时候就要蚕蛹泛型类型的方式定义,也就是类级别的泛型,语法格式如下:
public class GenericDao<T>{
priavate Tfield1;
public void save(T obj){}
public T getByld(int id){}
}
注:当一个变量被声明为泛型时,只能被实例变量和方法调用(还有内嵌类型),而不能被静态变量和静态方法调用,以为静态成员是被所有参数话的类所共享的,所以静态成员不应该有类级别的类型参数。如果静态方法确实需要泛型,可将其定义在静态方法自身上。
6.通过反射获得泛型的参数化类型:
需求:通过反射获取泛型类型中的实际化参数,如Vector<Date>所装的到底是什么元素
思路:
1.直接通过反射Vector的字节码文件,无法获得其具体参数类型,因为其字节码文件是去泛型化的,通过以下示例说明:
public class GenerticTest {
public static void main(String[] args) throws Exception{
ArrayList<String> al=new ArrayList<String>();
al.add("asdf");
al.getClass().getMethod("add",Object.class).invoke(al, 6);
System.out.println(al);
//打印结果为[asdf, 6]说明将6已经添加入al中
}
}
2.Method类中有方法可以获得带泛型的参数列表,如果将Vector<Date>作为参数传入某方法,即可以在其字节码文件中保留其泛型类型,具体例子如下:
package it.cast.day2;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Date;
import java.util.Vector;
public class GenerticTest3 {
public static void getVetorType(Vector<Date> v1){
}
public static void main(String[] args) throws NoSuchMethodException, SecurityException{
Type[] type=GenerticTest3.class.getMethod("getVetorType", Vector.class).getGenericParameterTypes();/*
获得getVetorType方法中带泛型类型的参数列表*/
ParameterizedType ptype=(ParameterizedType)type[0];//将参数类型列表中第一个类型参数,强制转换为其具体子类
System.out.println(ptype.getActualTypeArguments()[0]);/*打印表示Vector<Date>此类型实际类型参数的 Type 对象
的数组的第一个元素*/
System.out.println(ptype.getRawType());//打印表示声明此类型的类或接口
/*输出结果为class java.util.Date
class java.util.Vector*/
}
}