爱漫画-只做精品的韩漫网站,wordpress 简码使用,巩义云启网站建设,wordpress 编辑器 插件说明
author blog.jellyfishmix.com / JellyfishMIX - githubLICENSE GPL-2.0
获取泛型#xff0c;泛型擦除
下图中示例代码是一个工具类用于生成 csv 文件#xff0c;需要拿到数据的类型#xff0c;使用反射感知数据类型的字段#xff0c;来填充表字段名。可以看到泛型…说明
author blog.jellyfishmix.com / JellyfishMIX - githubLICENSE GPL-2.0
获取泛型泛型擦除
下图中示例代码是一个工具类用于生成 csv 文件需要拿到数据的类型使用反射感知数据类型的字段来填充表字段名。可以看到泛型 T 没有类似 getClass() 的方法因为编译后泛型 T 会被擦除在字节码中不存在 T 这个类型所以没办法通过 T 来获取某些信息。方法签名中的 java.util.ListT 编译后会变成 java.util.List。解决方式是显式传入 Class? clazz 来指定数据类型。 泛型嵌套
Class? clazz 只能传递一层数据类型无法解决泛型嵌套时的数据类型传递问题。对于泛型嵌套例如 ListListMapString, Person这样的类型。如果使用 Class? clazz 来传递只能感知到最外层的 List.class内层泛型还是会出现泛型擦除的情况。完整地传递泛型嵌套还是需要感知到具体的泛型。
TypeReference 原理分析–感知具体泛型
出现泛型嵌套情况时获取完整的泛型也是序列化组件需要面对的问题。解决方法例如 jackson 提供的 TypeReference。
泛型没有完全擦除
javac 编译后没有把所有持有泛型的位置都做擦除。编译后的字节码中子类的类签名显式指定了传递给父类的泛型。
根据子类获取向父类传递的泛型理论基础
作为 TypeReference 的替代品定义一个 CustomTypeHandler通过演义来展示 TypeReference 的原理
public abstract class CustomTypeHandlerT extends Object {
}再定义一个 ChildCustomTypeHandler 子类继承父类时声明泛型。
public class ChildCustomTypeHandler extends CustomTypeHandlerListListMapString, Person {private String tag;
}编译项目后使用 jclasslib(一个 IDEA 查看字节码的插件) 查看 ChildCustomTypeHandler.class 字节码发现 Attributes - Signature 属性中记录了类签名类签名显式指定了传递给父类的泛型。 class 文件结构
jvm 定义了 u1, u2, u4 三种数据结构来表示 1, 2, 4 字节无符号整数。class 文件采用类似 C 语言的结构体来存储数据如下所示:
ClassFile {u4 magic;u2 minor_version;u2 major_version;u2 constant_pool_count;cp_info constant_pool[constant_pool_count-1];u2 access_flags;u2 this_class;u2 super_class;u2 interfaces_count;u2 interfaces[interfaces_count];u2 fields_count;field_info fields[fields_count];u2 methods_count;method_info methods[methods_count];u2 attributes_count;attribute_info attributes[attributes_count];
}中文说明:
魔数(Magic Number)
版本号(MinorMajor Version)
常量池(Constant Pool)
类访问标记(Access Flags)
类索引(This Class)
超类索引(Super Class)
接口表索引(Interfaces)
字段表(Fields)
方法表(Methods)
属性表(Attributes)类的字节码 Attributes - Signature 属性中记录了类签名类签名会显式指定传递给父类的泛型。这是根据子类获取向父类传递的泛型的理论基础及 TypeReference 的理论基础。
根据子类获取向父类传递的泛型 demo
getActualTypeArguments 可能会存在多个泛型例如 MapK,V 所以会返回 Type[] 数组。根据 CustomTypeHandler 的约定只能向 CustomTypeHandler 传递一个最外层 T因此这里直接通过[0]拿 T。这里拿到的 T 是包含泛型嵌套的。例如子类声明 extends CustomTypeHandlerListListMapString, Person这里会拿到 ListListMapString, Person如果想继续拿嵌套的内层泛型可以继续调用 ParameterizedType#getActualTypeArguments
public abstract class CustomTypeHandlerT extends Object {protected final Type _type;/*** 此方法实际由子类调用*/protected CustomTypeHandler() {Type superClass getClass().getGenericSuperclass();// sanity check, should never happenif (superClass instanceof Class?) {throw new IllegalArgumentException(Internal error: TypeReference constructed without actual type information);}/** getActualTypeArguments 可能会存在多个泛型例如 MapK,V 所以会返回 Type[] 数组* 根据 CustomTypeHandler 的约定只能向 CustomTypeHandler 传递一个最外层 T因此这里直接通过[0]拿 T。* 这里拿到的 T 是包含泛型嵌套的。例如子类声明 extends CustomTypeHandlerListListMapString, Person这里会拿到 ListListMapString, Person* 如果想继续拿嵌套的内层泛型可以继续调用 ParameterizedType#getActualTypeArguments*/_type ((ParameterizedType) superClass).getActualTypeArguments()[0];}public Type getType() {return this._type;}
}扩展阅读
java Type 接口 https://blog.csdn.net/lvxiangan/article/details/94836504