使用java泛型设计通用方法
泛型是Java SE 1.5的新特性, 泛型的本质是参数化类型, 也就是说所操作的数据类型被指定为一个参数. 因此我们可以利用泛型和反射来设计一些通用方法. 现在有2张表, 一张user表和一张student表.
user:

student:

如果要根据id查询数据, 你会怎么做呢?写2个方法分别查询user和student?其实这时候我们就可以使用泛型和反射写一个通用的方法.
user的实体类:
private Integer id;
private String username;
private String password;
private String hobby;
//getXxx方法和setXxx方法
student实体类:
private Integer id;
private String name;
private Integer age;
//getXxx方法和setXxx方法
BaseDao接口:
public interface BaseDao<T> {
//根据id查询的方法
T findById(Integer id);
}
BaseDaoImpl类, 实现了BaseDao接口, 通用方法就在这里面完成:
//设置为抽象的, 不让他实例化, 让其子类实例化就行了
//通过泛型设计通用方法的关键就是利用反射拿到泛型的具体类型
public abstract class BaseDaoImpl<T> implements BaseDao<T> {
private String tableName; //表名
private Class<T> actualType;//真实类型 /**
* findById(Integer id)这个方法被子类继承了, 假设我们在UserDaoImpl中操作, 此时参数化类型T为User
* 下面的讲解都假设是在UserDaoImpl中进行的
*/
//把公共部分可以放到构造方法中
@SuppressWarnings("unchecked")
public BaseDaoImpl() {
//返回类型是Type 是 Java 编程语言中所有类型的公共高级接口. 它们包括原始类型、参数化类型、数组类型、类型变量和基本类型.
//Type的已知子接口: ParameterizedType 表示参数化类型, 如 Collection<String>.
//getClass()得到UserDaoImpl的Class, 得到Class一般有3中方式: getClass(), 类名.class, Class.forName()
Type type = getClass().getGenericSuperclass();//获取UserDaoImpl<User>的参数化类型的父类BaseDaoImpl<User>
//由于我们得到的是一个参数化类型, 所以转成ParameterizedType, 因为需要使用里面的方法
ParameterizedType pt = (ParameterizedType) type;//强转
Type[] actualTypeArr = pt.getActualTypeArguments();//获取真实参数类型数组[User.class], 可以调试看到这里的值
actualType = (Class<T>) actualTypeArr[0];//数组只有一个元素
tableName = actualType.getSimpleName();
} @Override
public T findById(Integer id) {
String sql = "select * from " + tableName + " where id = ?";
try {
return QRUtils.getQueryRunner().query(sql, new BeanHandler<T>(actualType), id);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
}
连接数据库操作是用的c3p0和dbutils, 有关这方面的内容可以参看我以前的随笔.
UserDao接口, 继承BaseDao接口:
public interface UserDao<T> extends BaseDao<T> {
}
UserDaoImpl类, 实现UserDao接口, 继承BaseDaoImpl类, 可以看到里面什么方法也没有:
public class UserDaoImpl extends BaseDaoImpl<User> implements UserDao<User> {
}
StudentDao接口, 继承BaseDao接口:
public interface StudentDao<T> extends BaseDao<T> {
}
StudentDaoImpl类, 实现StudentDao接口, 继承BaseDaoImpl类, 也可以看到里面什么方法也没有:
public class StudentDaoImpl extends BaseDaoImpl<Student> implements StudentDao<Student> {
}
从以上dao可以看到, 我是在继承BaseDaoImpl类时把泛型具体化了.
测试:
@Test
public void testGeneric() throws Exception {
UserDao<User> userDao = new UserDaoImpl();
System.out.println(userDao.findById(1)); System.out.println("-------------------");
StudentDao<Student> studentDao = new StudentDaoImpl();
System.out.println(studentDao.findById(1));
}
看一下测试的结果: 同一个方法把2张表中的数据都查出来了

有关泛型的基本使用, 请参考java泛型基础
使用java泛型设计通用方法的更多相关文章
- 初识Java泛型以及桥接方法
泛型的由来 在编写程序时,可能会有这样的需求:容器类,比如java中常见的list等.为了使容器可以保存多种类型的数据,需要编写多种容器类,每一个容器类中规定好了可以操作的数据类型.此时可能会有Int ...
- java导出excel通用方法
首先需要引入的jar包: 正式代码了. import java.io.FileOutputStream; import java.io.OutputStream; import java.net.UR ...
- Effective Java - [3. 对象通用方法]
Item 10. 若覆盖equals方法,需要遵守规则
- java泛型基础
泛型是Java SE 1.5的新特性, 泛型的本质是参数化类型, 也就是说所操作的数据类型被指定为一个参数. 这种参数类型可以用在类.接口和方法的创建中, 分别称为泛型类.泛型接口.泛型方法. Ja ...
- java 泛型的类型擦除与桥方法
泛型类 --代码参考:java核心技术 卷1 第十版 public class Pair<T> { private T first; private T second; //构造器 pub ...
- Java泛型-内部原理: 类型擦除以及类型擦除带来的问题
一:Java泛型的实现方法:类型擦除 大家都知道,Java的泛型是伪泛型,这是因为Java在编译期间,所有的泛型信息都会被擦掉,正确理解泛型概念的首要前提是理解类型擦除.Java的泛型基本上都是在编译 ...
- java泛型 8 泛型的内部原理:类型擦除以及类型擦除带来的问题
参考:java核心技术 一.Java泛型的实现方法:类型擦除 前面已经说了,Java的泛型是伪泛型.为什么说Java的泛型是伪泛型呢?因为,在编译期间,所有的泛型信息都会被擦除掉.正确理解泛型概念的首 ...
- Java泛型学习笔记--Java泛型和C#泛型比较学习(一)
总结Java的泛型前,先简单的介绍下C#的泛型,通过对比,比较学习Java泛型的目的和设计意图.C#泛型是C#语言2.0和通用语言运行时(CLR)同时支持的一个特性(这一点是导致C#泛型和Java泛型 ...
- java泛型(二)、泛型的内部原理:类型擦除以及类型擦除带来的问题
微信公众号[程序员江湖] 作者黄小斜,斜杠青年,某985硕士,阿里 Java 研发工程师,于 2018 年秋招拿到 BAT 头条.网易.滴滴等 8 个大厂 offer,目前致力于分享这几年的学习经验. ...
随机推荐
- Javascript正则对象方法与字符串正则方法总结
正则对象 var reg = new Regexp('abc','gi') var reg = /abc/ig 正则方法 test方法(测试某个字符串是否匹配) var str = 'abc123'; ...
- RMS Server打开或关闭日志记录
原文: https://technet.microsoft.com/zh-cn/library/cc732758 在 Active Directory Rights Management Servic ...
- Android AndroidRuntime类
AndroidRuntime类是安卓底层很重要的一个类,它负责启动虚拟机以及Java线程,AndroidRuntime类在一个进程中只有一个实例对象保存在全局变量,gCurRuntime中.
- git 命令总结
1 删除分支 git push origin :branch name(Task_******) //删除远程分支 git branch -D branch name(Task_******) ...
- U盘安装Kali 出现cd-rom无法挂载 已解决
用U盘安装Kali Linux的过程中,出现cd-rom无法挂载的现象,百度坑比啊,醉了.下面亲测成功 出现无法挂载后,选择执行shell 第一步:df -m此时会看到挂载信息,最下面的是/dev/* ...
- 《Ansible权威指南》笔记(2)——Inventory配置
四.Inventory配置ansible通过Inventory来定义主机和组,使用时通过-i指定读取,默认/etc/ansible/hosts.可以存在多个Inventory,支持动态生成.1.定义主 ...
- python-time 模块
1.时间戳是以秒为单位的浮点小数,时间戳以自1970年1月1日午夜到现在经过了的时间来表示 2.时间模块引入方式:import time 3.返回时间戳 time.time() 4.返回时间元组:ti ...
- ENode框架Conference案例分析系列之 - 文章索引
ENode框架Conference案例分析系列之 - 业务简介 ENode框架Conference案例分析系列之 - 上下文划分和领域建模 ENode框架Conference案例分析系列之 - 架构设 ...
- Kafka1 利用虚拟机搭建自己的Kafka集群
前言: 上周末自己学习了一下Kafka,参考网上的文章,学习过程中还是比较顺利的,遇到的一些问题最终也都解决了,现在将学习的过程记录与此,供以后自己查阅,如果能帮助到其他人,自然是更好的. ...
- Ford-Fulkerson 最大流算法
流网络(Flow Networks)指的是一个有向图 G = (V, E),其中每条边 (u, v) ∈ E 均有一非负容量 c(u, v) ≥ 0.如果 (u, v) ∉ E 则可以规定 c(u, ...