对于Java泛型,我们知道两点:
1. 泛型是JDK1.5以后才有的,可以在编译时期进行类型检查,将类和方法与所使用的类型之间的约束关系进行了解耦,从而可以编写更通用的代码。
2. 泛型只在编译时期有效,编译后的字节码文件中不存在有泛型信息!如果需要在运行时使用类型信息,需要显式地传递你的类型的Class对象来对泛型进行补偿。
下面的BaseDao就是通过泛型的反射来获得运行时的类型信息,从而编写更为通用的代码。
泛型反射涉及的API
包名:java.lang.reflect
接口 Type
已知子接口:
ParameterizedType
所有已知实现类:
Class
包名java.lang.reflect
接口 ParameterizedType
| getActualTypeArguments |
什么是参数化类型
ArrayList<String>这种形式就是参数化类型
BaseDao代码
其中连接池使用C3P0;
约定:
1. 实体类名 - 表名
2. 实体属性名 - 表中字段名
3. 主键名称必须叫id
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.SQLException;
import java.util.List;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import util.*;
/**
* 所有dao的公用的方法,都在这里实现
*
*/
public class BaseDao<T> {
// 保存当前运行类的参数化类型中的实际的类型
private Class clazz;
// 表名 约定表名就是实体类名 -- 在C#的BaseDAL中,是通过Lamda表达式传入表名的
private String tableName;
// 构造函数: 1. 获取当前运行类的参数化类型;
// 2. 获取参数化类型中实际类型的定义(class)
public BaseDao() {
// this 表示当前运行类 (AccountDao/AdminDao)
// this.getClass() 当前运行类的字节码对象(AccountDao.class/AdminDao.class)
// this.getClass().getGenericSuperclass(); 当前运行类的父类,即为BaseDao<Account>
// 其实就是“参数化类型”, ParameterizedType
//返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的直接超类的 Type
Type type = this.getClass().getGenericSuperclass();
// 强制转换为“参数化类型” 【BaseDao<Account>】
ParameterizedType pt = (ParameterizedType) type;
// Class类是Type接口的实现类
// 获取参数化类型中,实际类型的定义 【new Type[]{Account.class}】
Type types[] = pt.getActualTypeArguments();
// 获取数据的第一个元素:Accout.class
clazz = (Class) types[0];
// 表名 (与类名一样,只要获取类名就可以)
tableName = clazz.getSimpleName();
}
/**
* 主键查询
*
* @param id
* 主键值
* @return 返回封装后的对象
*/
@SuppressWarnings({"unchecked"})
public T findById(int id) {
/*
* 1. 知道封装的对象的类型 2. 表名【表名与对象名称一样, 且主键都为id】
*
* 即,得到当前运行类继承的父类 BaseDao<Account> ----》 得到Account.class
*/
String sql = "select * from " + tableName + " where id=? ";
try {
return JdbcUtils.getQuerrRunner().query(sql,
new BeanHandler<T>(clazz), id);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
/**
* 查询全部
*
* @return
*/
public List<T> getAll() {
String sql = "select * from " + tableName;
try {
return JdbcUtils.getQuerrRunner().query(sql,
new BeanListHandler<T>(clazz));
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
这样写完之后存在一个明显的问题,那就是前面的约定约束性太强了,如果数据库表和实体类名不是对应关系,该怎么做呢?