泛型是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泛型设计通用方法的更多相关文章

  1. 初识Java泛型以及桥接方法

    泛型的由来 在编写程序时,可能会有这样的需求:容器类,比如java中常见的list等.为了使容器可以保存多种类型的数据,需要编写多种容器类,每一个容器类中规定好了可以操作的数据类型.此时可能会有Int ...

  2. java导出excel通用方法

    首先需要引入的jar包: 正式代码了. import java.io.FileOutputStream; import java.io.OutputStream; import java.net.UR ...

  3. Effective Java - [3. 对象通用方法]

    Item 10. 若覆盖equals方法,需要遵守规则

  4. java泛型基础

    泛型是Java SE 1.5的新特性, 泛型的本质是参数化类型, 也就是说所操作的数据类型被指定为一个参数. 这种参数类型可以用在类.接口和方法的创建中, 分别称为泛型类.泛型接口.泛型方法.  Ja ...

  5. java 泛型的类型擦除与桥方法

    泛型类 --代码参考:java核心技术 卷1 第十版 public class Pair<T> { private T first; private T second; //构造器 pub ...

  6. Java泛型-内部原理: 类型擦除以及类型擦除带来的问题

    一:Java泛型的实现方法:类型擦除 大家都知道,Java的泛型是伪泛型,这是因为Java在编译期间,所有的泛型信息都会被擦掉,正确理解泛型概念的首要前提是理解类型擦除.Java的泛型基本上都是在编译 ...

  7. java泛型 8 泛型的内部原理:类型擦除以及类型擦除带来的问题

    参考:java核心技术 一.Java泛型的实现方法:类型擦除 前面已经说了,Java的泛型是伪泛型.为什么说Java的泛型是伪泛型呢?因为,在编译期间,所有的泛型信息都会被擦除掉.正确理解泛型概念的首 ...

  8. Java泛型学习笔记--Java泛型和C#泛型比较学习(一)

    总结Java的泛型前,先简单的介绍下C#的泛型,通过对比,比较学习Java泛型的目的和设计意图.C#泛型是C#语言2.0和通用语言运行时(CLR)同时支持的一个特性(这一点是导致C#泛型和Java泛型 ...

  9. java泛型(二)、泛型的内部原理:类型擦除以及类型擦除带来的问题

    微信公众号[程序员江湖] 作者黄小斜,斜杠青年,某985硕士,阿里 Java 研发工程师,于 2018 年秋招拿到 BAT 头条.网易.滴滴等 8 个大厂 offer,目前致力于分享这几年的学习经验. ...

随机推荐

  1. winform异步加载数据到界面

    做一个学习记录. 有两个需求: 1.点击按钮,异步加载数据,不卡顿UI. 2.把获取的数据加载到gridview上面. 对于需求1,2,代码如下: public delegate void ShowD ...

  2. CSS 3学习——transition 过渡

    以下内容根据官方规范翻译以及自己的理解整理. 1.介绍 这篇文档介绍能够实现隐式过渡的CSS新特性.文档中介绍的CSS新特性描述了CSS属性的值如何在给定的时间内平滑地从一个值变为另一个值. 2.过渡 ...

  3. IL异常处理

    异常处理在程序中也算是比较重要的一部分了,IL异常处理在C#里面实现会用到一些新的方法 1.BeginExceptionBlock:异常块代码开始,相当于try,但是感觉又不太像 2.EndExcep ...

  4. C#~异步编程再续~await与async引起的w3wp.exe崩溃-问题友好的解决

    返回目录 关于死锁的原因 理解该死锁的原因在于理解await 处理contexts的方式,默认的,当一个未完成的Task 被await的时候,当前的上下文将在该Task完成的时候重新获得并继续执行剩余 ...

  5. springmvc的拦截器

    什么是拦截器                                                         java里的拦截器是动态拦截action调用的对象.它提供了一种机制可以使 ...

  6. SAP CRM 显示消息/在消息中进行导航

    向用户展示消息,在任何软件中都是十分重要的. 在SAP CRM WEB UI中展示消息,不是一项很难的任务,只需要创建消息并在之后调用方法来显示它 消息类和消息号: 我在SE91中创建了如下的消息类和 ...

  7. node(ActiveMq)

    简单尝试了node下的ActiveMQ 1.下载apache-activemq-5.9.0,执行bat文件: 2.登录http://localhost:8161/admin可查看其管理后台: 3.安装 ...

  8. 写自己的socket框架(二)

    1.开始正常监听以后,就要开始接受数据了,整体流程图如下: 2.上一节看到我们在程序初始化的时候,初始化了很多个SocketConnection,用于管理客户端的链接,那应用层如何来操作,又什么时候来 ...

  9. IT公司的女流之辈

    声明:并不是对女性怎么怎么滴歧视, 我只是想陈述事实. 女性来IT公司工作, 真的适合吗? 如果是杰出女性也就罢了, 如果只是一般女性呢? 她能够像一般男性一样的 努力工作, 像牛马一样的工作? 在某 ...

  10. css3盒模型

    css2.1盒模型: 当你定义盒子的宽高后:如果添加padding和border值后盒子的宽高会被撑大 盒子的高度=定义的高度+(padding-top + padding-bottom)+(bord ...