使用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方法
View Code

 

  student实体类:

    private Integer id;
    private String name;
    private Integer age;
    //getXxx方法和setXxx方法
View Code

 

  BaseDao接口:

public interface BaseDao<T> {
    //根据id查询的方法
    T findById(Integer id);
}
View Code

 

  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> {
}
View Code

  UserDaoImpl类, 实现UserDao接口, 继承BaseDaoImpl类, 可以看到里面什么方法也没有:

public class UserDaoImpl extends BaseDaoImpl<User> implements UserDao<User> {
}
View Code

  StudentDao接口, 继承BaseDao接口:

public interface StudentDao<T> extends BaseDao<T> {
}
View Code

 

  StudentDaoImpl类, 实现StudentDao接口, 继承BaseDaoImpl类, 也可以看到里面什么方法也没有:

public class StudentDaoImpl extends BaseDaoImpl<Student> implements StudentDao<Student> {
}
View Code

  从以上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泛型基础

posted @ 2016-12-13 14:17  眺望小寒山  阅读(4801)  评论(0编辑  收藏  举报