获取泛型的class 反射
最近在使用Google的Gson包进行Json和Java对象之间的转化,对于包含泛型的类的序列化和反序列化Gson也提供了很好的支持,感觉有点意思,就花时间研究了一下。
由于Java泛型的实现机制,使用了泛型的代码在运行期间相关的泛型参数的类型会被擦除,我们无法在运行期间获知泛型参数的具体类型(所有的泛型类型在运行时都是Object类型)。
但是有的时候,我们确实需要获知泛型参数的类型,比如将使用了泛型的Java代码序列化或者反序列化的时候,这个时候问题就变得比较棘手。
|
1
2
3
4
5
6
7
8
|
class Foo<T> { T value;}Gson gson = new Gson();Foo<Bar> foo = new Foo<Bar>();gson.toJson(foo); // May not serialize foo.value correctlygson.fromJson(json, foo.getClass()); // Fails to deserialize foo.value as Bar |
对于上面的类Foo<T>,由于在运行期间无法得知T的具体类型,对这个类的对象进行序列化和反序列化都不能正常进行。Gson通过借助TypeToken类来解决这个问题。
|
1
2
3
4
5
6
7
8
|
TestGeneric<String> t = new TestGeneric<String>(); t.setValue("Alo"); Type type = new TypeToken<TestGeneric<String>>(){}.getType(); String gStr = GsonUtils.gson.toJson(t,type); System.out.println(gStr); TestGeneric t1 = GsonUtils.gson.fromJson(gStr, type); System.out.println(t1.getValue()); |
TypeToken的使用非常简单,如上面的代码,只要将需要获取类型的泛型类作为TypeToken的泛型参数构造一个匿名的子类,就可以通过getType()方法获取到我们使用的泛型类的泛型参数类型。
下面来简单分析一下原理。
要获取泛型参数的类型,一般的做法是在使用了泛型的类的构造函数中显示地传入泛型类的Class类型作为这个泛型类的私有属性,它保存了泛型类的类型信息。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public class Foo<T>{ public Class<T> kind; public Foo(Class<T> clazz){ this.kind = clazz; } public T[] getInstance(){ return (T[])Array.newInstance(kind, 5); } public static void main(String[] args){ Foo<String> foo = new Foo(String.class); String[] strArray = foo.getInstance(); }} |
这种方法虽然能解决问题,但是每次都要传入一个Class类参数,显得比较麻烦。Gson库里面对于这个问题采用了了另一种解决办法。
同样是为了获取Class的类型,可以通过另一种方式实现:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public abstract class Foo<T>{ Class<T> type; public Foo(){ this.type = (Class<T>) getClass(); } public static void main(String[] args) { Foo<String> foo = new Foo<String>(){}; Class mySuperClass = foo.getClass(); } } |
声明一个抽象的父类Foo,匿名子类将泛型类作为Foo的泛型参数传入构造一个实例,再调用getClass方法获得这个子类的Class类型。
这里虽然通过另一种方式获得了匿名子类的Class类型,但是并没有直接将泛型参数T的Class类型传进来,那又是如何获得泛型参数的类型的呢, 这要依赖Java的Class字节码中存储的泛型参数信息。Java的泛型机制虽然在运行期间泛型类和非泛型类都相同,但是在编译java源代码成 class文件中还是保存了泛型相关的信息,这些信息被保存在class字节码常量池中,使用了泛型的代码处会生成一个signature签名字段,通过 签名signature字段指明这个常量池的地址。
关于class文件中存储泛型参数类型的具体的详细的知识可以参考这里:http://stackoverflow.com/questions/937933/where-are-generic-types-stored-in-java-class-files
JDK里面提供了方法去读取这些泛型信息的方法,再借助反射,就可以获得泛型参数的具体类型。同样是对于第一段代码中的foo对象,通过下面的代码可以得到foo<T>中的T的类型:
|
1
2
3
|
Type mySuperClass = foo.getClass().getGenericSuperclass(); Type type = ((ParameterizedType)mySuperClass).getActualTypeArguments()[0];System.out.println(type); |
运行结果是class java.lang.String。
分析一下这段代码,Class类的getGenericSuperClass()方法的注释是:
Returns the Type representing the direct superclass of the entity (class, interface, primitive type or void) represented by thisClass.
If the superclass is a parameterized type, the Type object returned must accurately reflect the actual type parameters used in the source code. The parameterized type representing the superclass is created if it had not been created before. See the declaration of ParameterizedType for the semantics of the creation process for parameterized types. If thisClass represents either theObject class, an interface, a primitive type, or void, then null is returned. If this object represents an array class then theClass object representing theObject class is returned
概括来说就是对于带有泛型的class,返回一个ParameterizedType对象,对于Object、接口和原始类型返回null,对于数 组class则是返回Object.class。ParameterizedType是表示带有泛型参数的类型的Java类型,JDK1.5引入了泛型之 后,Java中所有的Class都实现了Type接口,ParameterizedType则是继承了Type接口,所有包含泛型的Class类都会实现 这个接口。
实际运用中还要考虑比较多的情况,比如获得泛型参数的个数避免数组越界等,具体可以参看Gson中的TypeToken类及ParameterizedTypeImpl类的代码。
获取泛型的class 反射的更多相关文章
- java 反射和泛型-反射来获取泛型信息
通过指定对应的Class对象,程序可以获得该类里面所有的Field,不管该Field使用private 方法public.获得Field对象后都可以使用getType()来获取其类型. Class&l ...
- java 编程基础 反射方式获取泛型的类型Fileld.getGenericType() 或Method.getGenericParameterTypes(); (ParameterizedType) ;getActualTypeArguments()
引言 自从JDK5以后,Java Class类增加了泛型功能,从而允许使用泛型来限制Class类,例如,String.class的类型实际上是 Class 如果 Class 对应的类暂时未知,则使 C ...
- Gson通过借助TypeToken获取泛型参数的类型的方法
最近在使用Google的Gson包进行Json和Java对象之间的转化,对于包含泛型的类的序列化和反序列化Gson也提供了很好的支持,感觉有点意思,就花时间研究了一下. 由于Java泛型的实现机制,使 ...
- java获取泛型信息
总结一下java中获取与泛型相关的信息的知识,不如说是使用方法.网上也有很多类似的优秀文章,这里主要做一个知识的总结.通过反射获取泛型信息的常见例子: //bean package testProje ...
- Gson通过借助TypeToken获取泛型参数的类型的方法(转)
最近在使用Google的Gson包进行Json和Java对象之间的转化,对于包含泛型的类的序列化和反序列化Gson也提供了很好的支持,感觉有点意思,就花时间研究了一下. 由于Java泛型的实现机制,使 ...
- Dao泛型设计和反射反型
(1)DAO泛型设计:当二哥或多个类中有类似的方法时,可以将这些累死的方法提出到类中,形式一个泛型父类 (2)反射反型:在泛型父类中获取子类的具体类型的过程,叫反射反型 package cn.itca ...
- JAVA 注解,泛型,反射获取泛型,并实例化
JAVA 的泛型加大了 编程的灵活性,在配合上反射,可以让我们省去大量的重复代码,当你用 SpringBoot 整合 JPA 的时候 你会发现,你的 DAO 层只需要继承 BaseDao,在显示标明泛 ...
- JAVA基础_反射获取泛型参数类型
我经常会想获取参数的实际类型,在Hibernate中就利用的这一点. domain: Person.java public class Person { // 编号 private Long id; ...
- java 结合反射、泛型、注解获取泛型对象
由于自己也不是特别的理解,不能做过多的解释,因为这些是问过老师做出来的,我还没有学到这里.如果有解释错误的 指出来我改正一下.见谅~(如果学到这里了,会完善) 工具类(SQLUtil)核心代码: pa ...
随机推荐
- WPF没落了吗?
从08年开始一直到现在,碰到所有的项目,我个人经手的,都用wpf开发. wpf应该说一直没有火过,一直平平淡淡. 个人为什么一直执着用wpf,开始使用是因公司项目,做了两年wpf开发,后来换工作一直搜 ...
- MRT与MRTS工具官宣退休,推荐使用HEG
今天错误的删除搞丢了之前下载的MRT与MRTS工具,浏览Modis官网下载时发现找不到了,后来在其官网上发现了这则通知,原来早已停止更新的MRT这次彻底退修了.通知原文如下~~~ The downlo ...
- HTTP请求头和响应头部包括的信息有哪些?
每个HTTP请求和响应都会带有相应的头部信息.默认情况下,在发送XHR请求的同时,还会发送下列头部信息: Accept:浏览器能够处理的内容类型 Accept-Charset:浏览器能够显示的字符集 ...
- B. Vasya and Isolated Vertices
链接 [http://codeforces.com/contest/1065/problem/B] 题意 给你n个点,m条边,让你找最多孤立点和最少孤立点,不能有自环路 分析 对于最少max(0,n- ...
- linux内核分析程序破解实践报告
- Linux内核学习期末总结(网课)
标签(空格分隔): 20135321余佳源 余佳源(原创作品转载请注明出处) <Linux内核分析> MOOC课程http://mooc.study.163.com/course/USTC ...
- SDN网络虚拟化、资源映射等相关论文粗读
1. Control Plane Latency with SDN Network Hypervisors: The Cost of Virtualization 年份:2016 来源:IEEE NE ...
- mybatis分页 -----PageHelper插件
对查询结果进行分页 一,使用limit进行分页 1.mybatis 的sql语句: <if test="page !=null and rows !=null"> li ...
- Atlas & mysql-proxy
Atlas https://github.com/Qihoo360/Atlas https://github.com/Qihoo360/Atlas/wiki/Installing-Atlas Atla ...
- Delphi7通过superobject解析JSON
1.通过delphi程序访问PHP事先写好的webservice(查询功能),webservice返回json格式数据. 2.通过superobject读取json数据 得到效果如下: //深层级的访 ...