在运行时获取泛型的类型
来源:互联网 发布:网络销售招聘58同城 编辑:程序博客网 时间:2024/05/21 15:02
Java 1.5在加入泛型支持时,为了保持兼容,采用的是擦除法实现,泛型的定义只在编译的时候有效,编译之后是没有保留泛型的类型信息的。所以,通常是无法在运行时获得泛型的类型活实例化泛型类的,如下面的代码都无法通过编译:
public class Test<T> {
public Test(){
T t = new T(); // error
Class<T> clazz = T.class; //error
T[] ts = new T[10]; //error
}
}
public Test(){
T t = new T(); // error
Class<T> clazz = T.class; //error
T[] ts = new T[10]; //error
}
}
然而,擦除法的实现存在一些特列,在这些特例情况下,Java会记录泛型的类型信息,并且可以通过反射的Api来获取。比如在各种持久化框架中广泛使用的BaseDao泛型类的写法,就利用一个泛型继承的特例:
public class BaseDAO<U> {
private Class<U> entityClass;
protected BaseDAO() {
// 获取泛型类型
Type type = getClass().getGenericSuperclass();
Type[] trueType = ((ParameterizedType) type).getActualTypeArguments();
this.entityClass = (Class<U>) trueType[0];
}
public U getById(Serializable id){
PersistenceManager pm = getPersistenceManager();
pm.setDetachAllOnCommit(true);
U object;
try{
object = pm.getObjectById(entityClass, id);
}catch (JDOObjectNotFoundException e) {
object = null;
}finally{
pm.close();
}
return object;
}
}
public class TagDAO extends BaseDAO<Tag>{
}
private Class<U> entityClass;
protected BaseDAO() {
// 获取泛型类型
Type type = getClass().getGenericSuperclass();
Type[] trueType = ((ParameterizedType) type).getActualTypeArguments();
this.entityClass = (Class<U>) trueType[0];
}
public U getById(Serializable id){
PersistenceManager pm = getPersistenceManager();
pm.setDetachAllOnCommit(true);
U object;
try{
object = pm.getObjectById(entityClass, id);
}catch (JDOObjectNotFoundException e) {
object = null;
}finally{
pm.close();
}
return object;
}
}
public class TagDAO extends BaseDAO<Tag>{
}
代码的关键是getGenericSuperclass方法,这个方法返回的类型为ParameterizedType,里面可以通过getActualTypeArguments来获取泛型的真正类型。
Jackson json中反序列化时,可以通过TypeReference传递容器中的泛型类型,也是利用了泛型继承的特例:
Map<Integer, ApkBean> map = mapper.readValue(jsonData, new TypeReference<Map<Integer, ApkBean>>(){});
TypeReference是一个泛型抽象类,在readValue的第二个方法中,传入了TypeReference的一个匿名子类实例,由此带入了Map的泛型信息。
除了泛型继承这种情况之外,还有另外两个特例,也可以获取ParameterizedType类型,继而获取到泛型的类型。一个是类的field可以通过getGenericType来获取:
public class Test {
private Map<String, Number> map;
public static void main(String[] args) throws NoSuchFieldException {
Class<?> clazz = Test.class;
Field field = clazz.getDeclaredField("map");
//取得泛型类型
Type type = field.getGenericType();
ParameterizedType ptype = (ParameterizedType)type;
System.out.println(ptype.getActualTypeArguments()[0]);
System.out.println(ptype.getActualTypeArguments()[1]);
}
}
private Map<String, Number> map;
public static void main(String[] args) throws NoSuchFieldException {
Class<?> clazz = Test.class;
Field field = clazz.getDeclaredField("map");
//取得泛型类型
Type type = field.getGenericType();
ParameterizedType ptype = (ParameterizedType)type;
System.out.println(ptype.getActualTypeArguments()[0]);
System.out.println(ptype.getActualTypeArguments()[1]);
}
}
另外就是方法的泛型参数可以通过getGenericParameterTypes来获取:
public class Test {
public static void main(String[] args) throws NoSuchMethodException {
Class<?> clazz = Test.class;
Method method = clazz.getDeclaredMethod("getGenericSample", Collection.class);
//取得泛型类型参数集
Type[] type = method.getGenericParameterTypes();
ParameterizedType ptype = (ParameterizedType)type[0];
type = ptype.getActualTypeArguments();
System.out.println(type[0]);
}
public void getGenericSample(Collection<Number> collection){
}
}
public static void main(String[] args) throws NoSuchMethodException {
Class<?> clazz = Test.class;
Method method = clazz.getDeclaredMethod("getGenericSample", Collection.class);
//取得泛型类型参数集
Type[] type = method.getGenericParameterTypes();
ParameterizedType ptype = (ParameterizedType)type[0];
type = ptype.getActualTypeArguments();
System.out.println(type[0]);
}
public void getGenericSample(Collection<Number> collection){
}
}
这两种特例的实用价值比较小,实际的代码hack中也比较少见。
0 0
- 在运行时获取泛型的类型
- 在运行时获取泛型的类型
- 如何在运行时获取泛型的类型
- Java 运行时如何获取泛型参数的类型
- Java 运行时如何获取泛型参数的类型
- Java 运行时如何获取泛型参数的类型
- java在运行时获取泛型实例的方法
- 如何用C++获取运行时变量的类型
- 获取运行时泛型的实际类型
- 获取运行时期的对象类型
- 获取泛型的类型
- 得到运行时类的泛型类型。
- 在运行时获取ibatIS执行的sql
- 关于IList类型与IList<T>在运行时类型转换失败的问题
- 获取在接口或者类上定义的泛型类型
- 获取运行在手机前台的应用程序
- 在编译期间获取类型的信息
- 在java中获取变量的类型
- maven常用插件: 打包源码 / 跳过测试 / 单独打包依赖项
- Scala学习笔记24【List的高效排序】
- 整理 iOS 9 适配中出现的坑(图文)
- android 中Bn 和Bp的区别
- maven 打包排除指定文件
- 在运行时获取泛型的类型
- emqttd介绍和集群安装
- JavaScript Date 函数
- Android性能相关常用命令收集
- SQLite备忘
- Spring Security(16)——基于表达式的权限控制
- Android 性能优化之使用MAT分析内存泄露问题
- HttpClient通信
- UIScrollView新手教程