l泛型(Generic) —泛形的作用
lJDK5中的泛形允许程序员在编写集合代码时,就限制集合的处理类型,从而把原来程序运行时可能发生问题,转变为编译时的问题,以此提高程序的可读性和稳定性(尤其在大型程序中更为突出)。
l注意:泛型是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据。但编译器编译完带有泛形的java程序后,生成的class文件中将不再带有泛形信息,以此使程序运行效率不受到影响,这个过程称之为“擦除”。
l泛形的基本术语,以ArrayList<E>为例:<>念着typeof
•ArrayList<E>中的E称为类型参数变量
•ArrayList<Integer>中的Integer称为
实际类型参数
•整个称为ArrayList<E>泛型类型
•整个ArrayList<Integer>称为参数化的类型ParameterizedType
l使用迭代器迭代泛形集合中的元素。
l使用增强for循环迭代泛形集合中的元素。
l存取HashMap中的元素。
l使用泛形时的几个常见问题:
•使用泛形时,泛形类型须为引用类型,不能是基本数据类型
•ArrayList<String> list = new ArrayList<Object>();错
•ArrayList<Object> list = new ArrayList<String>(); 错
•ArrayList<String> list = new ArrayList ();正确
•ArrayList list = new ArrayList<String>();正确
l
l
自定义泛形
——
泛型
方法
lJava程序中的普通方法、构造方法和静态方法中都可以使用泛型。方法使用泛形前,必须对泛形进行声明,语法:<T> ,T可以是任意字母,但通常必须要大写。<T>通常需放在方法的返回值声明之前。例如:
public static <T> void doxx(T t);
public <T,E,K> T get(T t,E e,K k);//
l注意:
•只有对象类型才能作为泛型方法的实际参数。
•在泛型中可以同时有多个类型,例如:
public static <K,V> V getValue(K key) { return map.get(key);}
l
自定义泛形
——
泛型
类和反射泛形
l如果一个类多处都要用到同一个泛型,这时可以把泛形定义在类上(即类级别的泛型),语法格式如下:
public class GenericDao<T> {
private T field1;
public void save(T obj){}
public <E,K> T getId(int id,T t,E t,K k){}//T在定义在了类上所以不需在声明
public static <T,K> T comp(T t,K k){}//静态方法单独声明
}
l注意,静态方法不能使用类定义的泛形,而应单独定义泛形。
应用:
//泛型类
public abstract class DaoSupport<T>{
//得到类型参数变量T的实际类型
protected Class<T> entityClass = getEntityClass();
//实际传入的参数类型在数据库中对应表的名称,用于在hibernate的查询中构建hql语句
protected String entityName= getEntityName(DaoSupport.this.entityClass);
//getClass得到调用该方法的运行时类,即继承DaoSupport的相应子类
public String getSubClass()
{
return getClass().getName();
}
// 得到类型参数变量T的实际类型
public Class<T> getEntityClass(){
// 返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的 Class。
Type parentType =getClass().getGenericSuperclass();
//判断父类是否是泛型类
if( parentType instanceof ParameterizedType)
{
ParameterizedType ptype = (ParameterizedType) parentType;
//得到参数类型数组中第一个参数的真实的类型,即DaoSupport<T>中T的真实类型
return (Class<T>)ptype.getActualTypeArguments()[0];
}
return null;
}
/* 获取实体的名称
* @param <E>泛型方法声明,因为是静态方法所以泛型方法需要单独声明,
* @param clazz 实体类
* @return 实体类claz在数据库中对应表的名称
* */
protected static <E> String getEntityName(Class<E> clazz){
//简单类型名称
String entityname = clazz.getSimpleName();
//如果该类上面有Entity注解,且注解中有值,则取该值为该类在数据库中对应的表名称
Entity entity = clazz.getAnnotation(Entity.class);
if(entity.name()!=null && !"".equals(entity.name())){
entityname = entity.name();
}
return entityname;
}
}
DaoSupport的子类:
public class GoodServiceImpl extends DaoSupport<Good>{
}
Good类
@Entity(name="Product")
public class Good {
private String id;
private String name;
get/set方法省略
}
测试代码:
@Test
public void getGenericClass() {
GoodServiceImpl service = new GoodServiceImpl();
//得到调用该方法的运行时类
System.out.println(service.getSubClass());
//GoodServiceImpl父类DaoSupport<T>中类型参数T的实际传入类型
Class clazz = service.getEntityClass();
//GoodServiceImpl父类DaoSupport<T>中类型参数T的实际传入类型的名称
System.out.println(clazz.getName());
//实体类clazz在数据库中对应表的名称
System.out.println(service.getEntityName(clazz));
}
测试结果:
com.liang.service.impl.GoodServiceImpl
com.liang.bean.Good
Product