java 反射 子类泛型的class

很早之前写过利用泛型和反射机制抽象DAO ,对其中获取子类泛型的class一直不是很理解。关键的地方是HibernateBaseDao的构造方法中的

[java] view plaincopy

  1. Type genType = getClass().getGenericSuperclass();
  2. Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
  3. entityClass =  (Class)params[0];

但是这个相对子类才会有用,而且那篇文章的HibernateBaseDao还不是abstract,如果一不小心实例化的话就会报异常。感觉java中通过反射取泛型的class还是挺复杂的,不过一旦取到的话就可以做很多事情了。

改进的例子和测试:

1.先定义接口(这里写的比较简单就一个方法,具体可以再增加)

[java] view plaincopy

  1. public interface BaseDao<T> {
  2. T get(String id);
  3. }

2.定义抽象类实现接口

[java] view plaincopy

  1. import java.lang.reflect.ParameterizedType;
  2. import java.lang.reflect.Type;
  3. public abstract class HibernateBaseDao<T> implements BaseDao<T> {
  4. private Class<T> entityClass;
  5. /**
  6. * 这个通常也是hibernate的取得子类class的方法
  7. *
  8. * @author "yangk"
  9. * @date 2010-4-11 下午01:51:28
  10. */
  11. public HibernateBaseDao() {
  12. Type genType = getClass().getGenericSuperclass();
  13. Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
  14. entityClass = (Class) params[0];
  15. }
  16. @Override
  17. public T get(String id) {
  18. try {
  19. return entityClass.newInstance();
  20. } catch (InstantiationException e) {
  21. // TODO Auto-generated catch block
  22. e.printStackTrace();
  23. } catch (IllegalAccessException e) {
  24. // TODO Auto-generated catch block
  25. e.printStackTrace();
  26. }
  27. return null;
  28. }
  29. }

子类的构造函数会调用父类的构造函数,所以当子类实例化的时候,父类的entityClass 已经得到了T.class。

3.定义一个entity

[java] view plaincopy

  1. public class Entity {
  2. private String name;
  3. public String getName() {
  4. return name;
  5. }
  6. public void setName(String name) {
  7. this.name = name;
  8. }
  9. }

4.定义entity的DAO

[c-sharp] view plaincopy

  1. public class EntityDao extends HibernateBaseDao<Entity> {
  2. public void otherOperation() {
  3. }
  4. }

可以在里面定义父类没有的,针对具体子类特殊的方法。

5.测试

[java] view plaincopy

  1. import static org.junit.Assert.assertNotNull;
  2. import org.junit.After;
  3. import org.junit.AfterClass;
  4. import org.junit.Before;
  5. import org.junit.BeforeClass;
  6. import org.junit.Test;
  7. public class JunitTest {
  8. @BeforeClass
  9. public static void setUpClass() throws Exception {
  10. }
  11. @AfterClass
  12. public static void tearDownClass() throws Exception {
  13. }
  14. @Before
  15. public void setUp() {
  16. }
  17. @After
  18. public void tearDown() {
  19. }
  20. /**
  21. * Test of getEClass method, of class tmp.
  22. */
  23. @Test
  24. public void testNewClass() {
  25. EntityDao testDao = new EntityDao();
  26. Entity e = testDao.get(null);
  27. assertNotNull(e);
  28. }
  29. }

运行,可以看到测试顺利通过。

注意:上面子类DAO的写法public class EntityDao extends HibernateBaseDao<Entity>

一定要在父类后面带上泛型,负责编译就会出错。

附:这是泛型擦拭法使得Generic无法获取自己的Generic Type类型。实际上BadClass<String>()实例化以后Class里面就不包括T的信息了,对于Class而言T已经被擦拭为Object,而真正的T参数被转到使用T的方法(或者变量声明或者其它使用T的地方)里面(如果没有那就没有存根),所以无法反射到T的具体类别,也就无法得到T.class。而getGenericSuperclass()是Generic继承的特例,对于这种情况子类会保存父类的Generic参数类型,返回一个ParameterizedType,这时可以获取到父类的T.class了,这也正是子类确定应该继承什么T的方法。

时间: 2024-11-03 22:03:08

java 反射 子类泛型的class的相关文章

2015第22周六Java反射、泛型、容器简介

Java的反射非常强大,传递class, 可以动态的生成该类.取得这个类的所有信息,包括里面的属性.方法以及构造函数等,甚至可以取得其父类或父接口里面的内容. obj.getClass().getDeclaredMethods();//取得obj类中自己定义的方法, 包括私有的方法. obj.getClass().getMethods();//取得obj类中自己定义的方法及继承过来的方法, 但私有方法得不到. 同样, 对field也是一样,obj.getClass().getDeclaredFi

java 反射和泛型

反射 在计算机科学中,反射是指计算机程序在运行时(Run time)可以访问.检测和修改它本身状态或行为的一种能力.[1]用比喻来说,反射就是程序在运行的时候能够"观察"并且修改自己的行为. 要注意术语"反射"和"内省"(type introspection)的关系.内省(或称"自省")机制仅指程序在运行时对自身信息(称为元数据)的检测:反射机制不仅包括要能在运行时对程序自身信息进行检测,还要求程序能进一步根据这些信息改变程序

java 反射和泛型-反射来获取泛型信息

通过指定对应的Class对象,程序可以获得该类里面所有的Field,不管该Field使用private 方法public.获得Field对象后都可以使用getType()来获取其类型. Class<?> type = f.getType();//获得字段的类型 但此方法只对普通Field有效,若该Field有泛型修饰,则不能准确得到该Field的泛型参数,如Map<String,Integer>; 为了获得指定Field的泛型类型,我们采用: Type gType = f.getG

java反射获得泛型参数getGenericSuperclass():获取到父类泛型的类型

public class Person<T> { } import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; public class Student extends Person<Student> { public static void main(String[] args) { Student st=new Student(); Class clazz=st.getClass();

java反射+java泛型,封装BaseDaoUtil类。供应多个不同Dao使用

当项目是ssh框架时,每一个Action会对应一个Service和一个Dao.但是所有的Ation对应的Dao中的方法是相同的,只是要查的表不一样.由于封装的思想,为了提高代码的重用性.可以使用java中的泛型+反射去实现最终的封装,将所有的Dao层的共同部分写一个BaseDaoUtil.而所有的Dao都继承这个类. 思路: ----->(1)反射+泛型 ----->(2)当生成子类对象(UserDao),调用空构造时(new UserDao()),子类的空构造会默认调用父类的空构造器(new

Java进阶(四)Java反射TypeToken解决泛型运行时类型擦除的问题解决

在开发时,遇到了下面这条语句,不懂,然习之. private List<MyZhuiHaoDetailModel> listLottery = new ArrayList<MyZhuiHaoDetailModel>(); Gson gson=new Gson(); JSONObject object=new JSONObject(callbackValue); listLottery =  gson.fromJson(object.getString("lists&quo

Java进阶 四 Java反射TypeToken解决泛型运行时类型擦除问题

在开发时,遇到了下面这条语句,不懂,然习之. private List<MyZhuiHaoDetailModel> listLottery = new ArrayList<MyZhuiHaoDetailModel>(); Gson gson=new Gson(); JSONObject object=new JSONObject(callbackValue); listLottery =  gson.fromJson(object.getString("lists&quo

利用Java反射机制和泛型,全自动解析json

有啦这个简直,太爽啦, 利用Java 反射机制,利用Class 就可以得到 类的 变量  Field[] fields=cls.getDeclaredFields(); 还可以通过类中 的方法名字 去执行这个方法 m1 = cls.getDeclaredMethod(getMothodName(fields[j].getName()), String.class); m1.invoke(result,json.getString(fields[j].getName()) ); 利用泛型 去获取这

Java反射的理解(六)-- 通过反射了解集合泛型的本质

Java反射的理解(六)-- 通过反射了解集合泛型的本质 上述写了那么多,我们可能会有个疑问,为什么要用反射,步骤比我们常规的加载类操作复杂多了,别急,这个问题我最后才解答,我们先来了解集合泛型的本质. 直接上代码: import java.lang.reflect.Method; import java.util.ArrayList; public class MethodDemo4 { public static void main(String[] args) { ArrayList li