使用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,目前致力于分享这几年的学习经验. ...
随机推荐
- [转]ThinkPHP中实例化对象M()和D()的区别,select和find的区别
1.ThinkPHP中实例化对象M()和D()的区别 在实例化的过程中,经常使用D方法和M方法,这两个方法的区别在于M方法实例化模型无需用户为每个数据表定义模型类,如果D方法没有找到定义的模型类,则会 ...
- Centos6.x 下安装Jexus独立版
操作步骤: #cd /tmp #wget linuxdot.net/down/jexus-5.8.1-x64.tar.gz 注:如果有新版本,则修改为相应版本号即可. #tar -zxvf jexus ...
- [DeviceOne开发]-do_LinearLayout组件使用技巧
一.摘要 今天跟大家主要来介绍一下DeviceOne中的do_linearlayout这个布局,在DeviceOne开发中,do_linearlayout这个布局是相当重要. 现在给大家来总结一下. ...
- .NET开发邮件发送功能的全面教程(含邮件组件源码)
今天,给大家分享的是如何在.NET平台中开发“邮件发送”功能.在网上搜的到的各种资料一般都介绍的比较简单,那今天我想比较细的整理介绍下: 1) 邮件基础理论知识 2) ...
- ABP框架 - 启动配置
文档目录 本节内容: 配置ABP 替换内置服务 配置模块 为一个模块创建配置 ABP在启动时,提供基础框架和模型来配置和模块化. 置ABP 在预初始化事件中进行配置,示例: kid1412注:XmlL ...
- idea怎么设置自己的名字和时间
1.直接修改idea64.exe.vmoptions 里面添加上 -Duser.name=yourname 重启即可生效 1.file - settings-Editor- File and Code ...
- LLBL Gen Pro 5.0 企业应用开发入门
Solutions Design 公司于2016年5月发布了LLBL Gen Pro 5.0,这个新版本的发布出乎于我的意料.我的猜想是从4.2升级到4.5,再升级5.x版本,主版本号的变更会给原有客 ...
- vue-router(2.0)
用Vue.js+vue-router创建单页应用是比较简单的.使用Vue.js时,我们就已经把组件组合成一个应用了,当你要把vue-router加进来,只要配置组件和路由映射,然后告诉vue-rout ...
- 高性能JavaScript--加载和执行(简要学习笔记一)
1.多数浏览器使用单一进程来处理用户界面刷新和JavaScript脚本的执行.所以同一时刻只能做同一件事.JavaScript执行过程耗时越久,浏览器等待相应的时间就越长. 2.<scrip ...
- Python标准模块--itertools
1 模块简介 Python提供了itertools模块,可以创建属于自己的迭代器.itertools提供的工具快速并且节约内存.开发者可以使用这些工具创建属于自己特定的迭代器,这些特定的迭代器可以用于 ...