获取泛型类运行时刻实际成员类型
来源:互联网 发布:mac os vmware 镜像 编辑:程序博客网 时间:2024/05/01 06:17
新的工作开始了,自己也做了一个规划,所以从现在开始要坚持写博客,以前也写,不过都是在QQ空间上,这次动真格的,好好的把自己平时遇到的、见过的、有趣的东西记下来,我相信,自己的规划能让自己活出个精彩。
由于编译擦除,运行时刻无法获得成员的真实类型
现在的工作主要是给移动端提供访问服务器的接口,那么多多少少的都要涉猎些和安卓苹果开发有关的东西,在准备给安卓APP提供接口的时候,我看到了这么一个东西:Gson,这个包是Google提供的,主要用来做Json和Java对象间的转化,主要是对包含泛型类的序列化和反序列化提供了非常好的支持,那么这里就涉及到一个问题:
- 因为Java的泛型机制,运行期间泛型参数类型会被擦除,那么当我们真的需要知道泛型参数类型的时候,该怎么做?
ok,先上一个例子,看看问题所在:
package com.bubbling; //我自己的冒泡工作室,BubblingStudioimport java.lang.reflect.Field;public class Test<T> { T para; public static void main(String[] args) { Test<String> t = new Test<>(); Field[] fs = t.getClass().getDeclaredFields(); for(Field f : fs) { System.out.println(f.getType()); } }}
代码非常简单,给结果看一下,一目了然:
因为编译擦除,很清楚的看到运行时刻属性para的类型是Object,那么如果在运行时刻要得到成员类型就变得比较麻烦,接下来介绍两种方法,原理均来自Gson,但是我并不想把Gson中的东西拷贝出来,我会用Java的方式来解读它们。
Class类型作为成员保存类型信息
第一种是常见的做法,就是在泛型类的构造函数中,要求显式的传入泛型类的Class类型作为其私有属性,由它来保存泛型类的类型信息。如下:
package com.bubbling;import java.lang.reflect.Field;public class Test<T> { Class<T> para; public Test(Class<T> type) { this.para = type; } public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException { Test<String> t = new Test<>(String.class); Field[] fs = t.getClass().getDeclaredFields(); for(Field f : fs) { System.out.println(f.get(t)); } }}
运行结果如下:
通过Class成功的保存了泛型类成员的实际类型,但是这个办法有一个不好的地方,就是每次创建实例的时候,都需要显示的传入一个Class,为了解决这个问题,还有一个更高端的方法。
利用Class字节码常量池中的signature签名
先上代码:
package com.bubbling;import java.lang.reflect.ParameterizedType;import java.lang.reflect.Type;public class Test<T> { Class<T> para; @SuppressWarnings("unchecked") public Test() { this.para = (Class<T>)getClass(); } public static void main(String[] args) { Test<String> t = new Test<String>() {}; Type myType = t.getClass().getGenericSuperclass(); Type[] types = ((ParameterizedType)myType).getActualTypeArguments(); for(Type type : types) { System.out.println(type); } }}
运行结果如下:
分析一下原理:
成功的关键点就在匿名子类,匿名子类将泛型类作为参数传入构造函数,然后通过getClass()方法获得这个子类的Class类型。
而问题的关键点在于虽然我们得到了匿名子类的Class类型,但是我们并没有直接把泛型参数的Class类型传入,那么是怎么获得泛型参数类型的呢?
原因是Java的Class字节码中存储了泛型参数的信息,虽然Java泛型机制会擦除类型信息,但是class文件中依然保存了泛型相关的信息,这些信息存在于字节码常量池中,并且所处位置被signature签名标识,通过这个签名字段指明泛型信息存储地址。
而JDK里也提供了若干方法读取这些泛型信息,通过反射可以得到具体的泛型参数类型。
泛型相关的反射API介绍
- getGenericSuperclass()
- 该方法会返回一个Type类型的对象,如果该Class对象带有泛型信息,实际Type类型为ParameterizedType,如果是Object、接口或者原始类型则返回null,对于数组class来说则返回Object.class。
- Type接口
- JDK1.5之后引入了泛型概念,所以Java中所有的Class都实现了Type接口,Parameterized继承自Type,并且所有包含泛型的Class类都会实现该接口。
- getActualTypeArguments()
- 该方法返回表示此类型实际类型参数的Type对象的数组,调用此方法的时候,应该先判断该类是否支持泛型。
2017年3月17日 胡楠 冒泡工作室:BubblingStudio
- 获取泛型类运行时刻实际成员类型
- 获取运行时泛型的实际类型
- 获取成员变量类型
- C++ RTTI(Run-Time Type Indentifiation,运行时刻类型识别)
- C++学习笔记之运行时刻类型识别RTTI
- *获取泛型中的实际类型
- java获取泛型参数实际类型
- java获取泛型的实际类型
- Java获取泛型的实际类型
- Unity3D运行时刻资源管理
- sizeof运行时刻
- Unity运行时刻资源管理
- Unity运行时刻资源管理
- 如何获取java中泛型参数的实际类型--反射获取
- js 时刻获取时间
- 获取现在时刻
- 运行时 动态获取成员变量
- 跳过编译器,获取泛型参数的实际类型
- visio 2013安装到Office.zh_cn\officeMUI.mis officemui.xml
- linux 命令合集
- jeesz分布式企业框架 javaWeb分布式架构 springmvc+mybatis+shiro dubbo zookeeper redis kafka app服务
- Java温习——面向对象第四部分
- 设置UIBarButtonItem的间距
- 获取泛型类运行时刻实际成员类型
- java InputStream读取数据问题
- 最大子数组问题
- 【Oracle】——大数据下分页方法
- V4L2框架分析学习
- Kali Linux安装
- C# MVC API 返回Json
- Express+MongoDB+Robomongo环境配置
- Android Preference初探,另一种布局方式