今天在看项目中对Hibernate封装的代码,有一段代码一开始不是很理解,通过搜索学到了一些新知识。
public abstract class HibernateGenericDao<T, ID extends Serializable> extends
HibernateDaoSupport implements GenericDao<T, ID> {
/** 持久化对象的实际类型 。 */
private Class<T> entityClass;
/**
* 构造函数(默认)
*/
public HibernateGenericDao() {
// 获取当前Class为泛型超类的第一个类型参数
this.entityClass = (Class<T>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}
/**
* 如需运行时变更持久化类型,可override本函数。
*
* @return 持久化对象类型
*/
public Class<T> getEntityClass() {
return entityClass;
}
...
}
这段代码不是我编写的,但应该是比较普遍的Hibernate接口封装的实现。
HibernateDaoSupport是Hibernate提供的持久化操作封装的基类,为了方便业务层编写,HibernateGenericDao是其第一层封装。重点关注这段代码。
public HibernateGenericDao() {
// 获取当前Class为泛型超类的第一个类型参数
this.entityClass = (Class<T>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}
getClass是获得当前类的运行时的类对象,可能是其任意一个子孙类的类对象。
getGenericSupperClass是获得类对象的直接父类的类对象,在本例中,因为HibernateGenericDao是一个虚类,在运行时必定由其子类调用其构造方法,所以这个直接父类就是它本身了。
而我们知道,HibernateGenericDao含有泛型参数:<T,ID extends Serializable>,所以做一个显示的类型转换(ParameterizedType)。
getActualTypeArguments(), 获得泛型参数列表,[0]获取第一个参数,就是实体类型,所以 (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];这一句就可以在运行时为不同的子类实现统一的操作。确实挺妙的。
像比如ParameterizedType, getGenericSupperClass(), getActualTypeArguments()这些类型和方法我以前都没有使用过。还是很菜啊! 记下来以后就会用了。 这类操作很适合在基类中为运行时的子类做统一处理。
ParameterizedType: 表示一个参数化类型,比如Collection<String>。参数化类型在创建实例时,它的泛型类型申明才会被解析,所有类型参数都被递归创建。