一、概念:
- 参数化类型,是JDK1.5的新特性。(定义泛型时使用参数可以简单理解为形参),例如List,Map<K,V>
- 编译时的一种类型,此类型仅仅在编译阶段有效,运行时无效.因此可以利用反射在运行时向泛型对象中存入泛型类型之外的数据.例如List在运行时String会被擦除,最终系统会认为都是Object.
二、使用泛型的优点:
泛型是进行类型设计或方法定义时的一种约束规范,基于此规范可以:
- 提高编程时灵活性;
- 提高程序运行时的性能,在编译阶段解决一些运行时需要关注的问题,例如强转;
三、泛型的应用类型:
泛型定义时常用方式有三种:
- 泛型类: class 类名<泛型,…>{}
- 泛型接口: interface 接口名<泛型,…>{}
- 泛型方法: 访问修饰符 <泛型>方法返回值类型 方法名(形参){}
类泛型应用:(用于约束类中方法参数和方法返回值类型)
class Container<T>{//类泛型:类名<泛型>
public void add(T t){}//通过类泛型约束方法参数类型
public T get(){//通过类泛型约束方法返回值类型
return null;
}
}
类泛型应用:关键代码分析
Container<Integer> c1=new Container<>();
c1.add(100);//自定封箱 Integer.valueOf(100)
//c1.add("ABC");
Integer t1=c1.get();
说明: 泛型应用时相当于实参传给形参,但是实参必须为对象类型。
接口泛型应用:
定义接口时指定泛型,用于约束接口方法参数类型以及方法返回值类型,这里无须关心此类要做什么,重点先了解语法.
interface Task<Param,Result>{//思考map中的泛型Map<K,V>
/**
* 此方法用于执行任务
* @param arg 其类型由泛型参数Param决定
* @return 其类型由泛型参数result决定
*/
Result execute(Param arg);
}
//接口泛型应用
class ConvertTask implements Task<String,Integer>{
@Override
public Integer execute(String arg) {
// TODO Auto-generated method stub
return Integer.parseInt(arg);
}
}
方法泛型应用:(用于约束方法参数和返回值类型)
class DefaultSqlSession{
/**泛型方法*/
public <T>T getMapper(Class<T> cls){
return null;
}
}
class ClassPathXmlApplicationContext{
//泛型方法:写一个getBean方法(仿照spring官方)
public <T>T getBean(Class<T> cls){
return null;
}
public <T>T getBean(String id,Class<T> cls){
return null;
}
}
总结:
- 泛型类和泛型接口用于约束类或接口中实例方法参数类型,返回值类型.
- 泛型类或泛型接口中实际泛型类型可以在定义子类或构建其对象时传入.
- 泛型方法用于约束本方法(实例方法或静态方法)的参数类型或返回值类型.
- 泛型类上的泛型不能约束类中静态方法的泛型类型.
四、泛型的通配符
通配符一般可以理解为一种通用的类型,在这里的通配符泛指一种不确定性类型.
- 泛型应用时有一个特殊符号”?”,可以代表一种任意参数类型(实参类型);
- 通配符泛型只能应用于变量的定义,例如:Class<?> c1;
例如:
public class TestGeneric05 {
public static void main(String[] args)throws Exception {
Class<Log> c1=Log.class; //类对象
//System.out.println(c1.toString());
//"?"为泛型应用的一个通配符
//当泛型应用时,无法判定具体类型时,使用"?"替代
//此案例在编译阶段根本无法确定字符串中代理的类型具体为何种类型.
Class<?> c2=Class.forName("com.java.generic.Log");
//Class<Log> c3=Class.forName("com.java.generic.Log"); 错误
System.out.println(c1==c2);
}
}
五、泛型的上下界:
泛型在应用时通常要指定对象的上届和下届,其实现方式如下:
- 指定泛型下界: <? super 类型>
- 指定泛型上界: <? extends 类型>
例如:分析对错
List<Object> list1=new ArrayList<String>(); 错误
List<String> list2=new ArrayList<Object>(); 错误
List<? extends CharSequence> list1=new ArrayList<String>(); 正确
List<? super Integer> list2=new ArrayList<Number>();正确
说明: 这种上下界一般会用于方法参数变量定义,方法返回值类型定义。
案例实现:类中方法定义
class PrintUtil{
static void doPrint(List<? extends CharSequence> list){
System.out.println(list);
}
static void doPrint(Set<? super Integer> set){
System.out.println(list);
}
}
六、泛型类型擦除:
泛型是编译时的一种类型,在运行时无效,运行时候都会变成Object类型.因此可以利用反射在运行时向泛型对象中存入泛型类型之外的数据.
例如:
@Test
public void testGeneric01(){
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
//list.add(200);//此时直接加int类型,编译时会报错的
//利用泛型运行时类型擦除来加入其它类型
Class<?> cls = list.getClass();
Method method = cls.getDeclaredMethod("add",Object.class);//泛型运行时类型为Object
method.invoke(list,200);
System.out.println(list);
}