zoukankan      html  css  js  c++  java
  • 使用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泛型基础

    唯一激励你前行的是你的心
  • 相关阅读:
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    详解以太坊世界状态
    VDF 不是工作量证明
    以太坊:Go-Ethereum: 编译运行
    【转】理解分布式账本技术: 经济学视角
    Counterfactual 项目:广义的以太坊状态通道
    Solidity 安全:已知攻击方法和常见防御模式综合列表
    Verge 攻击解析
    以太坊区块链的轻客户端
  • 原文地址:https://www.cnblogs.com/pdzbokey/p/6169726.html
Copyright © 2011-2022 走看看