Tin's Blog

You are coming a long way, baby~Thinking, feeling, memory...

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  128 随笔 :: 0 文章 :: 221 评论 :: 0 Trackbacks

江南白衣的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的方法。
我们应该利用这种特性,这对实现模版方法非常有用。
posted on 2006-05-08 21:37 Tin 阅读(2559) 评论(3)  编辑  收藏 所属分类: Other Project

评论

# re: 范型擦拭法即范型类无法获取范型参数信息的原因 2006-05-28 21:25 差沙
哦,这么说来faint的例子其实使用了一个障眼法。其实GoodClass里面的String跟new GoodClass<String>中的String没有任何关系。

getGenericSuperclass取到的也是extend 时候的String。  回复  更多评论
  

# re: 范型擦拭法即范型类无法获取范型参数信息的原因 2006-05-29 16:15 Tin
恩,我是这么理解的。主要就是因为泛型是编译期的,运行期本应该是不可用的。获取getGenericSuperclass则是特例,此时由于编译顺序造成不能编译后马上擦除T的信息,所以保留了一个ParameterizedType,所以我们就有幸得到它了。:D  回复  更多评论
  

# re: 范型擦拭法即范型类无法获取范型参数信息的原因 2006-11-08 00:51 江南白衣
另外有些可以情况可以反射,比如如果是在属性中定义的泛型

class BookManager{

Book<String> book;
}

这个时候用Field field = BookManager.class.getDeclaredField("book");取得Field
然后 Type gtype = field.getGenericType();
if (gtype instanceof ParameterizedType)
....同上  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: