江南白衣的Blog上一篇:
Java5泛型的用法,T.class的獲取和為擦拭法站臺(tái)
他參考的這里:
Generic Data Access Objects
我們的項(xiàng)目中也用的GenericHibernateDAO,里面使用了一個(gè):
public
?GenericHibernateDAO(
final
?Class
<
E
>
?clazz)?{
????????
this
.clazz?
=
?clazz;
????}
的構(gòu)造函數(shù)。
但是看了江南白衣的介紹,的確方便的可以寫成:
public?GenericHibernateDAO()?{
????????this.clazz?=?(Class<E>)?((ParameterizedType)?getClass()
?????????????????????????????????????????????????????????.getGenericSuperclass()).getActualTypeArguments()[0];
????}
這樣,繼承的子DAO就可以不用寫Super(xxx.class)進(jìn)行構(gòu)造了。
其中的:
(Class
<E>)?((ParameterizedType)?getClass().getGenericSuperclass()).getActualTypeArguments()[0];?
非常神奇,看了faint的一個(gè)回復(fù)(請參照白衣的Blog):
package?test;?
import?java.lang.reflect.ParameterizedType;?
import?java.lang.reflect.Type;?
import?junit.framework.TestCase;?
class?TClass<T>?{?
}?
class?GoodClass<T>?extends?TClass<String>?{?
public?ParameterizedType?getClassT()?{?
return?(ParameterizedType)?getClass().getGenericSuperclass();?
}?
}?
class?BadClass<T>?extends?TClass<T>?{?
public?ParameterizedType?getClassT()?{?
return?(ParameterizedType)?getClass().getGenericSuperclass();?
}?
}?
public?class?GenericsTest?extends?TestCase?{?
private?void?print(Type[]?targs)?{?
System.out.print("actual?type?arguments?are:");?
for?(int?j?=?0;?j?<?targs.length;?j++)?{?
System.out.print("?instance?of?"?+?targs[j].getClass().getName()?+?":");?
System.out.println("?("?+?targs[j]?+?")");?
}?
}?
public?void?testGoodClass()?throws?Exception?{?
ParameterizedType?type?=?new?GoodClass<String>().getClassT();?
Type[]?types?=?type.getActualTypeArguments();?
print(types);?
assertEquals(TClass.class,?type.getRawType());?
assertEquals(String.class,?types[0]);?
}?
public?void?testBadClass()?throws?Exception?{?
ParameterizedType?type?=?new?BadClass<String>().getClassT();?
Type[]?types?=?type.getActualTypeArguments();?
print(types);?
assertEquals(TClass.class,?type.getRawType());?
assertEquals(String.class,?types[0]);?
}?
}
例子中的 BadClass 非常有意思,無法獲取T的實(shí)際類型,我試驗(yàn)了半天也得不到。
看到也有朋友問這個(gè)問題:
http://forum.java.sun.com/thread.jspa?threadID=684429&messageID=3985573納悶,怎么就不行呢。
翻了翻候捷的這篇文章:
http://www.jjhou.com/javatwo-2004-GP-in-jdk15.pdf才恍然大悟,原來對于BadClass這種情況就是獲取不了它的Class。
這是擦拭法的本意。
實(shí)際上BadClass<String>()實(shí)例化以后Class里面就不包括T的信息了,對于Class而言T已經(jīng)被擦拭為Object。而真正的T參數(shù)被轉(zhuǎn)到使用T的方法(或者變量聲明或者其它使用T的地方)里面(如果沒有那就沒有存根,這里指ParameterizedTyp),所以無法反射到T的具體類別,也就無法得到T.class。
而getGenericSuperclass()是Generic繼承的特例,對于這種情況子類會(huì)保存父類的Generic參數(shù)類型,返回一個(gè)ParameterizedType,這時(shí)可以獲取到父類的T.class了,這也正是子類確定應(yīng)該繼承什么T的方法。
我們應(yīng)該利用這種特性,這對實(shí)現(xiàn)模版方法非常有用。