黑马程序员_java之泛型
泛型
泛型:JDK1.5版本以后出现的新特性。用于解决安全问题,是一种类型安全机制。
好处:1、把运行期间出现的问题转移到编译时期,方便解决问题,安全
2、避免强制转换的麻烦
泛型理解:Java泛型类似C++模板,相似限于表面;基本完全在编译器中实现;用于编译器执行类型检查和类型推断(编译器判断泛型方法的实际类型参数的过程);编译泛型集合时会除掉“类型”信息,运行效率不受影响,对于参数化的泛型类型,getClass()返回值和原始类型完全一样;只要跳过编译器,就可往泛型集合中加入其它类型的数据。如反射得到集合,再调用其add方法即可。
如反射得到集合,再调用其add方法即可。
ArrayList<Integer> collection3=new ArrayList<Integer>();
System.out.println(collection2.getClass()==collection3.getClass());
collection3.getClass().getMethod("add",Object.class).invoke(collection3,"abc");
System.out.println(collection3.get(0));
泛型术语:
ArrayList< E> 整个称为泛型类型 E类型变量/参数ArrayList原始类型
ArrayList<Integer> 整个 参数化的类型 Integer实例类型参数/类型参数的实例 <>念typeof
参数化类型与原始类型的兼容性:
参数化类型可引用一个原始类型的对象,编译报告警告
Collection<String> c=new Vector();//编译器一句话的事
原始类型可引用一个参数化类型的对象,编译报告警告
Collection c=new Vector<String>();//原来的方法接受一集合个参数,新的类型也要传过去
例:Vector v1=new Vector<String> ();//没错
Vector <Object> v=v1;//没错,v1为原始类型,编译器严格语法检查一句句扫描而非执行
参数化类型不考虑类型参数的继承关系
Vector<String> v=new Vector<Object> ();//错
Vector<Object> v=new Vector<String> ();//错
创建数组实例时,数组元素不能使用参数化类型
Vector<Integer> vlist[]=new Vector<Integer>[10];//错
泛型的通配符与泛型限定:
例:打印任意参数化类型集合中的所有数据
public static void printCollection(Collection<?> collection){
System.out.println(collection.size());
for(Object obj:collection){
System.out.println(obj);
}
//collection.add(1) 不能调用,与类型有关
// collection=new HashSet<Date>()对;编译器严格语法检查
}
<?> 中的? 是占位符,不明确类型,引用各种参数化类型,可调用与参数化无关的方法,不可调用与参数化有关的方法; 泛型里<T>中的T代表具体类型,
泛型限定:主要是为了提高扩展性。
? extends E :可接受E类型或E的子类 上限
//如addAll(Collection<? extends E> c)
Vector<? extends Number> x=new Vector<Integer> ();
? super E :可接受E类型或E的父类 下限
//如TreeSet(Comparator<? super E> comparator)
Vector<? super Integer > x=new Vector< Number > ();
自定义泛型方法及其应用:
<>修饰符之后返回值之前;应用泛型和定义泛型可使用泛型限定
定义泛型可同时有多个类型参数,用逗号隔开
public static <K,V> V getValue(K key){…return map.get(key);}
泛型通常体现形式:泛型类、泛型方法(含构造)、静态方法泛型、泛型接口、泛型限定
创建数组实例时,数组元素不能使用参数化类型
类型变量表示异常成为参数化异常,可用于throws列表中但不能用于catch子句中
public static<T extends Exception> void sayHello() throws T{
try {
} catch (Exception e) {
throw (T)e;
}
}
自定义泛型方法的练习与类型推断总结
把任意参数类型的一个数组中数据安全复制到相应类型的集合中
public static <T> void copy1(Collection<T> dest,T[] src){}
把任意参数类型的一个数组中数据安全复制到相应类型的另一个数组中
public static <T> void copy2(T[] dest,T[] src){}
应用:copy1(new Vector<String>(),new String[10]);
copy2(new Date[10],new String[10]);//取交集
//copy1(new Vector<Date>(),new String[10]);
类型参数的类型推断:
根据实际传递的参数类型或返回值的类型推断
某个类型参数只在参数列表的所有参数或返回值一处被应用,根据调用方法时传的实参或返回值
如swap(new String[3],1,2) static <T> void swap(T[] a,int i,int j)
某个类型参数在参数列表的所有参数或返回值多处被应用,若调用方法时应用类型为同一种
如add(3,5) static <T> T add(T a,T b)
某个类型参数在参数列表的所有参数或返回值多处被应用,若调用方法时应用类型为不同且无返回值,取参数的最大交集类型
fill(new Integer[3],3.5f )static <T> void fillArray(T[]a,T obj)//Number 编译没问题,运行有问题
某个类型参数在参数列表的所有参数或返回值多处被应用,若调用方法时应用类型为不同且有返回值,优先考虑返回值类型
Number x=add(3,3.5f) static <T> T add(T a,T b)
参数类型推断有传递性
copy1(new Vector<Date>(),new String[10])//出错
static <T> void copy(Collection<T> dest,T[] src){}
通过反射获得泛型的实际类型参数
应用:如把查询出来的数据库的数据转成所需要的类型
//Vector<Date> v1=new Vector<Date>();
//v1.getClass().不能得到v1元素类型,因为泛型在编译时会去参数化(类型信息)
Method applyMethod=GenericTest.class .getMethod("applyVector", Vector.class);
Type [] types=applyMethod.getGenericParameterTypes();
ParameterizedType pType= (ParameterizedType)types[0];
System.out.println(pType.getRawType());//原始类型
System.out.println(pType.getActualTypeArguments()[0]); //类型参数
}
public static void applyVector (Vector<Date> v1){}