Java通过Class的对象来获取泛型的class示例

本文介绍如何通过Java反射机制获取泛型类型Class对象,并提供了一个具体的实现示例。
在使用spring的JdbcTemplate实现DAO的时候,经常会用到一个类ParameterizedBeanPropertyRowMapper。它的静态方法newInstance()接受一个Class类型的参数,用于将ResultSet中的属性映射到传入的这个Class类型的Bean对象中,再组成列表返回。
 
如果要想把这个DAO做成泛型的,就必须要知道Class的类型。但是直接写成T.class显然是不行的。从网上查了不少资料,结果只有一个,由于Java的泛型实现使用了“擦拭法”(具体细节没深究,呵呵),导致Java的泛型不能直接获取到自身的声明的泛型类型。
 
不过从江南白衣的blog文章里搜到了有用的东西:使用反射来获得“T.class”。
原文地址:http://www.blogjava.net/calvin/archive/2009/12/10/43830.html
 
主要用到的是这么一句:
[c-sharp] view plain copy
Class <T> entityClass = (Class <T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];   


 
我查询了Java API,在Class类中有这么两个方法: getGenericInterfaces()和getGenericSuperclass()
 
先来看看这两个方法都是干什么用的:
 
1. public Type getGenericSuperclass()
用来返回表示当前Class 所表示的实体(类、接口、基本类型或 void)的直接超类的Type。如果这个直接超类是参数化类型的,则返回的Type对象必须明确反映在源代码中声明时使用的类型。比如:
[java] view plain copy
package com.mot.hyena.test;  
import java.lang.reflect.ParameterizedType;  
public class GT1 extends GT2<Integer>{  
    public static void main(String[] args) {  
        System.out.println(((ParameterizedType)new GT1().getClass().getGenericSuperclass()));  
    }  
}  
则输出结果即为:com.mot.hyena.test.GT2<java.lang.Integer>
 
如果此Class代表的是Object 类、接口、基本类型或 void,则返回 null。。如果此对象表示一个数组类,则返回表示 Object 类的 Class 对象。
 
2. public Type[] getGenericInterfaces()
与上面那个方法类似,只不过Java的类可以实现多个接口,所以返回的Type必须用数组来存储。
 
 
以上两个方法返回的都是Type对象或数组,在我们的这个话题中,Class都是代表的参数化类型,因此可以将Type对象Cast成ParameterizedType对象。而 ParameterizedType对象有一个方法, getActualTypeArguments()。
public Type[] getActualTypeArguments()
用来返回一个Type对象数组,这个数组代表着这个Type声明中实际使用的类型。接着使用上面的例子:
[java] view plain copy
package com.mot.hyena.test;  
import java.lang.reflect.ParameterizedType;  
public class GT1 extends GT2<Integer>{  
    public static void main(String[] args) {  
    System.out.println(((ParameterizedType)new GT1().getClass().getGenericSuperclass()).getActualTypeArguments()[0]);  
    }  
}  
这次的显示结果将是:class java.lang.Integer
 
因此,我们可以通过继承+反射的方法,来的到T.class。
 
需要说明的是,江南白衣使用的方法是将关键语句
Class < T >  entityClass  =  (Class < T > ) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[ 0 ];
放在了超类,也就是声明泛型的那个类的构造方法中。这样一来,子类在继承具有泛型的超类时,会自动调用超类的构造方法。在此超类的构造方法中,调用的getClass返回的是子类的Class类型(与通常的重写机制有悖,呵呵,有待深究,但测试结果确是如此),则在子类中就无需再显式地使用 getGenericInterfaces()和getGenericSuperclass()等方法了。
 

接着,再使用(Class<T>)对 getActualTypeArguments()返回的元素做casting,即可得到所谓的T.class。


----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

完整示例:

Java通过Class的对象来获取泛型的class示例

[java]  view plain  copy
 print ?
  1. /** 
  2. * 创建一个Class的对象来获取泛型的class 
  3.  */  
  4. private Class<T> clz;  
  5.       
  6. @SuppressWarnings("unchecked")  
  7. public Class<T> getClz(){  
  8.     if (clz==null) {  
  9.         clz=(Class<T>)(((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);  
  10.     }  
  11.     return clz;  
  12. }  

此方法一般在模板方法中经常用到,因此做一个笔记!


<think>好的,用户想了解如何通过Java反射获取方法返回值的Class及其信息。我需要先回顾一下反射相关的知识,特别是关于的处理。根据提供的引用,反射可以获取方法返回值的信息,比如使用Method的getGenericReturnType方法。 首先,用户需要获取方法的返回值。对于普通,直接使用method.getReturnType()就能得到Class对象。但如果返回值带有,比如List<String>,就需要处理参数。这时候应该用method.getGenericReturnType(),返回的是Type,可能需要检查是否是ParameterizedType实例,然后提取实际的参数。 引用1和引用2提到了getGenericReturnType方法,并展示了如何检查ParameterizedType以及获取其中的Type参数。比如,如果返回是List<String>,ParameterizedType的getActualTypeArguments()会返回String对应的Type。需要注意的是,如果是通配符或者其他复杂,可能需要更深入的处理,但根据用户的问题,可能只需要基础的情况。 引用3指出方法返回值的是可以通过反射获取的三个场景之一,这说明这是标准做法。引用4提到反射将Java成分映射成,比如Method代表方法,所以使用Method的方法是正确的路径。 接下来,我需要将这些步骤分点说明,确保用户能一步步操作。首先获取Method对象,然后分别处理普通。对于,要检查是否为ParameterizedType,并提取实际参数。可能还要提到Type的进一步处理,比如获取原始(raw type)的Class对象。 用户可能还关心如何获取参数的具体Class,比如从List<String>中获取String.class。这时需要将Type转换为Class,可能需要判断是否为Class实例(对于简单)或者TypeVariable(对于未指定的),但用户的问题可能更关注已指定的具体,如String。 需要注意的是,如果在运行时被擦除,反射可能无法获取到具体的信息,除非该在父接口中有明确的声明。例如,如果方法返回的是某个带有,而这个在子中被具体化,那么可以通过反射获取到具体的参数。但如果是局部变量或方法内部定义的,可能无法获取。这一点可能需要提醒用户,但根据提供的引用,似乎用户的问题集中在如何从方法声明中获取信息,比如方法返回明确为List<String>的情况。 总结步骤: 1. 获取目标方法的Method对象。 2. 使用getReturnType()获取返回值的Class。 3. 使用getGenericReturnType()获取信息。 4. 检查是否为ParameterizedType,如果是,提取实际参数。 5. 对每个参数进行处理,可能需要递归处理嵌套。 此外,需要给出代码示例,比如获取方法对象,处理普通,并输出结果。确保代码中的注释清晰,用户能理解每一步的作用。 可能的问题点:如何处理嵌套,例如Map<String, List<Integer>>,这时候实际参数可能包含另一个ParameterizedType,需要递归处理。但用户的问题可能不需要这么复杂,所以示例可以保持简单,如List<String>。 最后,生成相关问题,例如获取方法参数的、处理擦除的影响等,参考引用中的其他内容。</think>### 如何通过Java反射获取方法返回值的Class信息? #### 1. 获取方法返回值的Class 使用`Method.getReturnType()`方法可直接获取方法返回值的**原始**对应的`Class`对象。例如: ```java Method method = MyClass.class.getMethod("getStringList"); Class<?> returnClass = method.getReturnType(); System.out.println("返回值:" + returnClass.getName()); // 输出 java.util.List ``` #### 2. 获取方法返回值的信息 若返回值包含(如`List<String>`),需通过`Method.getGenericReturnType()`获取信息。返回的`Type`对象需进一步判断是否为`ParameterizedType`: ```java Type genericReturnType = method.getGenericReturnType(); if (genericReturnType instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) genericReturnType; // 获取实际参数 Type[] actualTypeArgs = parameterizedType.getActualTypeArguments(); for (Type typeArg : actualTypeArgs) { if (typeArg instanceof Class) { Class<?> genericClass = (Class<?>) typeArg; System.out.println("参数:" + genericClass.getName()); // 输出 java.lang.String } } } ``` #### 3. 处理嵌套参数本身是(如`Map<String, List<Integer>>`),需递归解析: ```java Type firstArgType = actualTypeArgs[0]; if (firstArgType instanceof ParameterizedType) { ParameterizedType nestedType = (ParameterizedType) firstArgType; Type[] nestedArgs = nestedType.getActualTypeArguments(); // 继续解析嵌套... } ``` #### 4. 注意事项 - **擦除**:若未在/方法声明中明确指定(如通过父继承),则无法通过反射获取具体[^3]。 - **原始**:`getReturnType()`返回原始(如`List.class`),而`getGenericReturnType()`返回带信息的(如`List<String>`)。 #### 完整示例 ```java public class Test { public List<String> getStringList() { return new ArrayList<>(); } public static void main(String[] args) throws NoSuchMethodException { Method method = Test.class.getMethod("getStringList"); // 获取原始 Class<?> returnClass = method.getReturnType(); System.out.println("原始:" + returnClass.getName()); // 输出 java.util.List // 获取信息 Type genericType = method.getGenericReturnType(); if (genericType instanceof ParameterizedType) { ParameterizedType pt = (ParameterizedType) genericType; Type[] actualTypes = pt.getActualTypeArguments(); for (Type actualType : actualTypes) { if (actualType instanceof Class) { System.out.println("参数:" + ((Class<?>) actualType).getName()); // 输出 java.lang.String } } } } } ``` #### 引用说明 - `Method.getGenericReturnType()`用于获取包含信息的返回值[^1][^2]。 - 反射仅支持成员变量、方法参数和返回值的[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值