江南白衣的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的方法。
我们应该利用这种特性,这对实现模版方法非常有用。