使用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泛型基礎