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