java泛型T.class的獲取
很早之前寫過利用泛型和反射機制抽象DAO ,對其中獲取子類泛型的class一直不是很理解。關鍵的地方是HibernateBaseDao的構造方法中的
- Type genType = getClass().getGenericSuperclass();
- Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
- entityClass = (Class)params[0];
但是這個相對子類才會有用,而且那篇文章的HibernateBaseDao還不是abstract,如果一不小心例項化的話就會報異常。感覺java中通過反射取泛型的class還是挺複雜的,不過一旦取到的話就可以做很多事情了。
改進的例子和測試:
1.先定義介面(這裡寫的比較簡單就一個方法,具體可以再增加)
- publicinterface BaseDao<T> {
- T get(String id);
- }
2.定義抽象類實現介面
- import java.lang.reflect.ParameterizedType;
- import java.lang.reflect.Type;
- publicabstractclass HibernateBaseDao<T> implements BaseDao<T> {
-
private
- /**
- * 這個通常也是hibernate的取得子類class的方法
- *
- * @author "yangk"
- * @date 2010-4-11 下午01:51:28
- */
- public HibernateBaseDao() {
- Type genType = getClass().getGenericSuperclass();
-
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
- entityClass = (Class) params[0];
- }
- @Override
- public T get(String id) {
- try {
- return entityClass.newInstance();
- } catch (InstantiationException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- returnnull;
- }
- }
子類的建構函式會呼叫父類的建構函式,所以當子類例項化的時候,父類的entityClass 已經得到了T.class。
3.定義一個entity
- publicclass Entity {
- private String name;
- public String getName() {
- return name;
- }
- publicvoid setName(String name) {
- this.name = name;
- }
- }
4.定義entity的DAO
- publicclass EntityDao extends HibernateBaseDao<Entity> {
- publicvoid otherOperation() {
- }
- }
可以在裡面定義父類沒有的,針對具體子類特殊的方法。
5.測試
- importstatic org.junit.Assert.assertNotNull;
- import org.junit.After;
- import org.junit.AfterClass;
- import org.junit.Before;
- import org.junit.BeforeClass;
- import org.junit.Test;
- publicclass JunitTest {
- @BeforeClass
- publicstaticvoid setUpClass() throws Exception {
- }
- @AfterClass
- publicstaticvoid tearDownClass() throws Exception {
- }
- @Before
- publicvoid setUp() {
- }
- @After
- publicvoid tearDown() {
- }
- /**
- * Test of getEClass method, of class tmp.
- */
- @Test
- publicvoid testNewClass() {
- EntityDao testDao = new EntityDao();
- Entity e = testDao.get(null);
- assertNotNull(e);
- }
- }
執行,可以看到測試順利通過。
注意:上面子類DAO的寫法public class EntityDao extends HibernateBaseDao<Entity>
一定要在父類後面帶上泛型,負責編譯就會出錯。
附:這是泛型擦拭法使得Generic無法獲取自己的Generic Type型別。實際上BadClass<String>()例項化以後Class裡面就不包括T的資訊了,對於Class而言T已經被擦拭為Object,而真正的T引數被轉到使用T的方法(或者變數宣告或者其它使用T的地方)裡面(如果沒有那就沒有存根),所以無法反射到T的具體類別,也就無法得到T.class。而getGenericSuperclass()是Generic繼承的特例,對於這種情況子類會儲存父類的Generic引數型別,返回一個ParameterizedType,這時可以獲取到父類的T.class了,這也正是子類確定應該繼承什麼T的方法。