江南白衣的Blog上一篇:
Java5泛型的用法,T.class的获取和为擦拭法站台
他参考的这里:
Generic Data Access Objects
我们的项目中也用的GenericHibernateDAO,里面使用了一个:
public
GenericHibernateDAO(
final
Class
<
E
>
clazz) {
this
.clazz
=
clazz;
}
的构造函数。
但是看了江南白衣的介绍,的确方便的可以写成:
public GenericHibernateDAO() {
this.clazz = (Class<E>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}
这样,继承的子DAO就可以不用写Super(xxx.class)进行构造了。
其中的:
(Class
<E>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
非常神奇,看了faint的一个回复(请参照白衣的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的实际类型,我试验了半天也得不到。
看到也有朋友问这个问题:
http://forum.java.sun.com/thread.jspa?threadID=684429&messageID=3985573纳闷,怎么就不行呢。
翻了翻候捷的这篇文章:
http://www.jjhou.com/javatwo-2004-GP-in-jdk15.pdf才恍然大悟,原来对于BadClass这种情况就是获取不了它的Class。
这是擦拭法的本意。
实际上BadClass<String>()实例化以后Class里面就不包括T的信息了,对于Class而言T已经被擦拭为Object。而真正的T参数被转到使用T的方法(或者变量声明或者其它使用T的地方)里面(如果没有那就没有存根,这里指ParameterizedTyp),所以无法反射到T的具体类别,也就无法得到T.class。
而getGenericSuperclass()是Generic继承的特例,对于这种情况子类会保存父类的Generic参数类型,返回一个ParameterizedType,这时可以获取到父类的T.class了,这也正是子类确定应该继承什么T的方法。
我们应该利用这种特性,这对实现模版方法非常有用。