泛型的补偿实例--使用泛型反射创建BaseDao

对于Java泛型,我们知道两点:

1.      泛型是JDK1.5以后才有的,可以在编译时期进行类型检查,将类和方法与所使用的类型之间的约束关系进行了解耦,从而可以编写更通用的代码。

2.      泛型只在编译时期有效,编译后的字节码文件中不存在有泛型信息!如果需要在运行时使用类型信息,需要显式地传递你的类型的Class对象来对泛型进行补偿。

下面的BaseDao就是通过泛型的反射来获得运行时的类型信息,从而编写更为通用的代码。

 

泛型反射涉及的API

包名:java.lang.reflect

接口 Type

已知子接口:

         ParameterizedType

所有已知实现类:

         Class

 

包名java.lang.reflect

接口 ParameterizedType

 Type[]

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.*;

/**
 * 所有dao的公用的方法,都在这里实现
 * 
 */
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();
	}

	/**
	 * 主键查询
	 * 
	 * @param id
	 *            主键值
	 * @return 返回封装后的对象
	 */
	@SuppressWarnings({"unchecked"})
	public T findById(int id) {
		/*
		 * 1. 知道封装的对象的类型 2. 表名【表名与对象名称一样, 且主键都为id】
		 * 
		 * 即,得到当前运行类继承的父类 BaseDao ----》 得到Account.class
		 */

		String sql = "select * from " + tableName + " where id=? ";
		try {
			return JdbcUtils.getQuerrRunner().query(sql,
					new BeanHandler(clazz), id);
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 查询全部
	 * 
	 * @return
	 */
	public List getAll() {
		String sql = "select * from " + tableName;
		try {
			return JdbcUtils.getQuerrRunner().query(sql,
					new BeanListHandler(clazz));
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}
}

这样写完之后存在一个明显的问题,那就是前面的约定约束性太强了,如果数据库表和实体类名不是对应关系,该怎么做呢?

参考:使用注解反射实现BaseDao

你可能感兴趣的:(JavaEE)