论坛首页 入门技术论坛

请教关于得到泛型的class

浏览 7823 次
精华帖 (2) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-07-14  
在发帖之前,一直在考虑。该不该发。查了查我的问题。也没有找到一个解决方案。所以,还是来发帖了。就发在新手帖吧。也许真的只是一个新手的问题。


先描述一下问题。有这个一个类:
public class Test<T>
{
}

要得到T的class。
如果看到这,请继续看下文,千万不要给出一句:
[color=red]
Class<T> entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; 
[/color]
的答复。因为,我已经试过了。

一直没有仔细研究泛型这个东西。所以直接上网查了。
基本上找到这样一个方法:
Class<T> entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; 


于是,依葫芦画瓢:
public class Test<T>
{
	Class<T> clazz;

	public Test()
	{
		clazz = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	}
	
	public static void main(String[] args)
	{
		Test<Integer> t = new Test<Integer>();
	}
}


执行后抛出异常如下:
Exception in thread "main" java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
	at Test.<init>(Test.java:9)
	at Test.main(Test.java:14)


查找原因。发现,java中的泛型采用擦拭法。无法得到自己本身的泛型。而调用getGenericSuperclass()方法得到的是父类的泛型
所以,再次修改代码:
class Father<T>
{
	
}

public class Test<T> extends Father<T>
{
	Class<T> clazz;

	public Test()
	{
		clazz = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
		//((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments();
	}
	
	public static void main(String[] args)
	{
		Test<Integer> t = new Test<Integer>();
	}
}


运行后出现如下异常:
Exception in thread "main" java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
	at Test.<init>(Test.java:14)
	at Test.main(Test.java:20)

这下郁闷了。按道理说,这个是没有问题的。
于是我再次修改代码。把15行的注释打开,把14行注释掉。于是,代码如下:
class Father<T>
{
	
}

public class Test<T> extends Father<T>
{
	Class<T> clazz;

	public Test()
	{
		//clazz = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
		((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments();
	}
	
	public static void main(String[] args)
	{
		Test<Integer> t = new Test<Integer>();
	}
}

这次,没有抱任何异常。那么也就是说:getActualTypeArguments()[0] 无法强制转化成为Class<T>类型。乖乖,我本来就要得到这个类型。现在就差一步之遥了。

请问,我该如何得到了?



   发表时间:2008-07-18  
自己找到了解决方法。有2种方式。
1:
先有一个父类
public class Father<T>
{
	Class<T> clazz;

	@SuppressWarnings("unchecked")
	public Father()
	{
		clazz = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	}
}



然后有一个子类:
public class Test1 extends Father<Integer>
{
	public Test1()
	{
		System.out.println(clazz);
	}

	public static void main(String[] args)
	{
		Test1 t = new Test1();
	}
}

2 请登录后投票
   发表时间:2008-07-18  
解决方法2:

一个类就可以了。不过这个有点投机。
public class Test2<T>
{
	Class<T> clazz;

	@SuppressWarnings("unchecked")
	public Test2(Class<T> clazz)
	{
		this.clazz = clazz;
		System.out.println(clazz);
	}

	public static void main(String[] args)
	{
		Test2<Integer> t = new Test2<Integer>(Integer.class);
	}
}

1 请登录后投票
   发表时间:2008-07-18  

总结。
对于解决方法1,要注意这样几点。
1). 只能取得父类的T.class,而且,要写一个子类,且子类在继承父类的时候,就要把类型给确定下来。即: 

public class Test extends Father<Integer>
{
}

 

这样的话,其实Test在定义的时候就已经确定了类型了。

2). 这种方式不灵活,非得一个父类,一个子类。那么如果有一个Dao

public class Dao<T>
{
	Class clazz;

	public Dao()
	{
		clazz = (Class) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	}
}

 

如果要针对具体类型的时候,那么就得一个子类

public class UserDao extends Dao 
{ 
}

 

同理,如果要操作多个对象,那么就有多个子类。这样,很冗余。

对于解决方式2,
1). 只需要一个类。而能解决所有的问题。

public class Test <T>
{
} 

 

2). 这个类需要一个带参数的构造。且这个参数就是泛型的class。也就是说,这个泛型的class是由外面传进去的。

public class Test <T>
{
	Class clazz;

	public Test(Class clazz)
	{
		this.clazz = clazz;
	}
}

 


3). 这种方式没有冗余。同样,以一个Dao来举例。

public class Dao<T>
{
	Class clazz;

	public Dao(Class clazz)
	{
		this.clazz = clazz;
	}
}

 
这样,如果有一个UserDao,我们只需要。

Dao userDao = new Dao(User.class); 

 

4). 这种方式对应于c++中的template更为接近。

  

 c++中:

template <class T>
class Dao 
{ 
public: 
    Dao()    {} 
    ~Dao()  {} 
}; 

int main(int argc, char* argv[]) 
{ 
     Dao* dao = new Dao; 
     delete dao; 
	
     return 0; 
} 

 
java中:

public class Dao<T>
{
	Class clazz;

	public Dao(Class clazz)
	{
		this.clazz = clazz;
	}

	public static void main(String[] args)
	{
		Dao dao = new Dao(User.class);
	}
}

 

两者唯一的区别在于。
1). c++代码中的构造方法可以不用参数,是一个默认构造就可以了。至于具体的是什么类型的参数。这个是在编译器编译成2进制文件时自动转化。

2). java代码中的构造方法,需要传递一个Class,这个Class就是T的Class。表面上看,好像这样子不合理。但是实际上想想,也没有不合理的地方。因为

Dao<User> dao = ...

 

这个地方的时候,你就已经确定了是对User进行操作。那构造方法中传递一个User.Class,又有何不可呢?

综上,采用2种方式中的任意一种都可以。不过,我更加喜欢第2种。


 

1 请登录后投票
   发表时间:2008-09-26  
不是不行,只是有点Ugly
0 请登录后投票
   发表时间:2008-12-22  
public abstract class BaseDAOImpl<T> extends JpaDaoSupport implements
IBaseDao<T> {

protected String className = "";


@SuppressWarnings("unchecked")
protected BaseDAOImpl() {
TypeVariable[] typeVariables = getClass().getTypeParameters();
if (typeVariables != null && typeVariables.length > 0) {
className = typeVariables[0].getName();
}
}
...
}
0 请登录后投票
   发表时间:2008-12-24  
也正在查这个问题,楼主这篇文章帮助很大,谢谢
0 请登录后投票
论坛首页 入门技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics