经常看到那些写好的项目的dao是用的泛型,就不不理解为什么,看到了这个论坛上的两个例子,粘给大家:
泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。
Java语言引入泛型的好处是安全简单。
在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。
泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。
泛型在使用中还有一些规则和限制:
1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。
2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。
3、泛型的类型参数可以有多个。
4、泛型的参数类型可以使用extends语句,例如<T extends superclass>。习惯上成为“有界类型”。
5、泛型的参数类型还可以是通配符类型。例如Class<?> classType = Class.forName(java.lang.String);
若对每张表都编写一套增删改差方法未必有些麻烦,并且不符合编码的基本准则。一般,我们可以将这些功能的所公用的部分封装为一个对象,或者是类,此类是所有DAO的基类,可以称为:BaseDAO。
由于此类接收到不同的操作对象,故需泛型的支持。
下面,我通过以下实例代码,为此知识进行展示,供大家参考
此例是基于ssh2的环境中进行搭建:
相关类:涉及到BaseDAO接口,接口实现类:BaseDAOImpl、两个数据表的操作对象及相应的接口:DAOA、DAOB、DAOAImpl、DAOBImpl
BaseDAO:接口代码,公共方法的接口类
package base;
import java.util.List;
public interface BaseDao<T> {
/**
* 保存实体
*
* @param entity
*/
void save(T entity);
/**
* 删除实体
*
* @param id
*/
void delete(Long id);
/**
* 更新实体
*
* @param entity
*/
void update(T entity);
/**
* 按id查询
*
* @param id
* @return
*/
T getById(Long id);
/**
* 按id查询
*
* @param ids
* @return
*/
List<T> getByIds(Long[] ids);
/**
* 查询所有
*
* @return
*/
List<T> findAll();
}
BaseDAOImpl:公共方法的实现类
package base;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import javax.annotation.Resource;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
@SuppressWarnings("unchecked")
public abstract class BaseDaoImpl<T> implements BaseDao<T> {
@Resource
private SessionFactory sessionFactory;
private Class<T> clazz;
public BaseDaoImpl() {
// 使用反射技术得到T的真实类型
ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass(); // 获取当前new的对象的 泛型的父类 类型
this.clazz = (Class<T>) pt.getActualTypeArguments()[0]; // 获取第一个类型参数的真实类型
System.out.println("clazz ---> " + clazz);
}
/**
* 获取当前可用的Session
*
* @return
*/
protected Session getSession() {
return sessionFactory.getCurrentSession();
}
public void save(T entity) {
getSession().save(entity);
}
public void update(T entity) {
getSession().update(entity);
}
public void delete(Long id) {
Object obj = getById(id);
if (obj != null) {
getSession().delete(obj);
}
}
public T getById(Long id) {
return (T) getSession().get(clazz, id);
}
public List<T> getByIds(Long[] ids) {
return getSession().createQuery(//
"FROM User WHERE id IN (:ids)")//
.setParameterList("ids", ids)//
.list();
}
public List<T> findAll() {
return getSession().createQuery(//
"FROM " + clazz.getSimpleName())//
.list();
}
}
DAOA:vo A的DAO接口类,此类需要继承BaseDAO接口,实现公共类,另外在此可以声明自己特有的方法
package dao;
import pojo.A;
import base.BaseDao;
public interface DAOA extends BaseDao<A>{
//...
}
DAOAImpl:vo A的DAO实现类,实现DAOA中声明的方法和BaseDAO的所以基本方法,为实现基本方法,故继承了BaseDaoImpl类
package dao.impls;
import org.springframework.stereotype.Repository;
import pojo.A;
import base.BaseDaoImpl;
import dao.DAOA;
@Repository
public class DAOAImpl extends BaseDaoImpl<A> implements DAOA {
}
同理,DAOB同上
以此,便完成了公共方法的继承与实现机制。
当中用到了泛型机制,通过继承父类来实现泛型的数据转换:
public class DAOAImpl extends BaseDaoImpl<A>{} A为vo的模型类,以此在父类中可调用实现!!
通过使用泛型T减少Dao的冗余代码,当T继承某个对象时(T extends EntityDao)限制了参数类型必须继承该对象(EntityDao),并且ClassT必须要有泛型参数(DeptDaoImpl extends ClassT<Dept>),否则转换失败。