在讲阿里fastjson 之前,先讲下泛型的一些基础知识和在反射中如何获取泛型,觉得自己已经掌握的可以直接通过目录跳到最后查看
泛型类的定义只要在申明类的时候,在类名后面直接加上< E>,中的E可以是任意的字母,也可以多个,多个用逗号隔开就可以。示例代码如下
public class SelfList<E> {} 复制代码
那么什么时候确定这个E 的具体类型呢?其实是在new 一个对象的时候指定的,请看下面代码
public class SelfList<E> { public void add(E e) { if (e instanceof String) { System.out.println(" I am String"); } else if (e instanceof Integer) { System.out.println("I am Integer"); } } public static void main(String[] args) { //这里创建的时候指定了String SelfList<String> a = new SelfList<String>(); a.add("123"); //这里创建的时候指定了Integer SelfList<Integer> b = new SelfList<Integer>(); b.add(123); } } 复制代码
泛型接口和类的使用方式一样
public interface IndicatorTypeService<T> {} //这里定义的时候指定具体类型为ProductSale,当然也可以这里没有指定具体类型 public class ProductSaleServiceImpl implements IndicatorTypeService<ProductSale> {} 复制代码
这个我觉得是相对来说比较难得,大家集中注意力听我说,说不定你以前一直以为的泛型方法是假的。好,先给个假的泛型方法给大家验一下,还是上面代码的例子,为了方便阅读我再贴一遍代码
//注意这是个假的泛型方法,不要以为有一个E就是泛型方法哦 public void add(E e) { if (e instanceof String) { System.out.println(" I am String"); } else if (e instanceof Integer) { System.out.println("I am Integer"); } } 复制代码
好了,重点来了,给个真正的泛型方法定义出来
public <T> T get(T t) { return t; } 复制代码
public <T> T get(T t) { return t; } public static void main(String[] args) { //这里创建的时候指定了String SelfList<String> a = new SelfList<String>(); a.add("123"); int num = a.get(123); } 复制代码
那么泛型方法是怎么确定这个具体类型的呢? 主要思想是在调用该泛型方法传进去的参数类型和返回值类型来确定具体类型的
public <T> T get1(T t) { if (t instanceof String) { System.out.println(" I am String"); } else if (t instanceof Integer) { System.out.println("I am Integer"); } return t; } public static void main(String[] args) { SelfList<String> a = new SelfList<String>(); //这里调用的时候传进去的是int 类型,所以确定了他的类型是int int b=a.get1(123); } 复制代码
输出结果
I am Integer 复制代码
public <T> T get2(T t, T t2) { if (t instanceof Float) { System.out.println(" I am String"); } else if (t instanceof Integer) { System.out.println("I am Integer"); } else if (t instanceof Number) { System.out.println("I am Number"); } return t; } public static void main(String[] args) { SelfList<String> a = new SelfList<String>(); //这里返回值类型必须是number 类型 Number b = a.get2(123, 12.1); } 复制代码
注意上面的输出还会是
I am Integer 复制代码
因为根据第一条规则,传进去的是什么类型就是什么类型,但是返回值类型候需要根据第二条规则来确定
上面说的都是在编译之前就可以确定的泛型。大家知道,泛型运行的时候其实是会被擦除的。不过没关系,还是提供给我们通过反射的方式来获取。首先我来认识下java中的泛型类型继承结构
这里主要讲平时运用最多的三个类,其他还有一些GenericArrayType 之类的就不讲了,大家按着我这个分析的思路去看下就可以
public interface ParameterizedType extends Type { /** * 返回一个实际类型的数组 * 比如对于ArrayList<T>,被实例化的时候ArrayList<String>,这里返回的就是String * */ Type[] getActualTypeArguments(); /** * 这里其实就是返回去掉泛型后的真实类型 * 对于List<T> 这里返回就是List */ Type getRawType(); /** * 这里针对的是内部类的情况,返回的是他的外层的类的类型 * 例如SelfHashMap 里面有一个Entry 内部类,也就是SelfHashMap.Entry<String,String> * 返回的就是SelfHashMap */ Type getOwnerType(); } 复制代码
定义一个有内部类的类
public class SelfHashMap { public static class Entry<T, V extends Collection> { } } 复制代码
public class ParameterizedTypeTest { public static void main(String[] args) { Class clazz = A.class; //注意这里是拿父类的泛型,jdk 没有提供本类的泛型 Type type = clazz.getGenericSuperclass(); if (type instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) type; System.out.println(Arrays.toString(parameterizedType.getActualTypeArguments())); System.out.println(parameterizedType.getRawType()); System.out.println(parameterizedType.getOwnerType()); } } /** * 这里的泛型被是指定了为String 和List * getActualTypeArguments() 会输出 String 和List */ public static class A extends SelfHashMap.Entry<String, List> { } } 复制代码
输出结果
[class java.lang.String, interface java.util.List] class com.wizhuo.jdklearning.reflect.dto.SelfHashMap$Entry class com.wizhuo.jdklearning.reflect.dto.SelfHashMap 复制代码
public interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement { /** * 这里返回的是泛型的上界类型数组,比如 <T, V extends Collection> 这里的上界类型就是Collection */ Type[] getBounds(); /** * 返回的是声明该泛型变量的类,接口,方法等 * 列如 public static class Entry<T, V extends Collection> 返回的就是Entry */ D getGenericDeclaration(); /** * 这里返回的就是泛型定义的变量名称,比如 <T> 返回的就是T * */ String getName(); /** * 这里返回的就是AnnotatedType 数组,jdk1.8 才加进来,本文不分析,直接跳过 */ AnnotatedType[] getAnnotatedBounds(); } 复制代码
public class TypeVariableTest { public static void main(String[] args) { Class clazz = SelfHashMap.Entry.class; TypeVariable[] typeVariables = clazz.getTypeParameters(); for (TypeVariable ty :typeVariables) { System.out.println(ty.getName()); System.out.println(Arrays.toString(ty.getAnnotatedBounds())); System.out.println((Arrays.toString(ty.getBounds()))); System.out.println(ty.getGenericDeclaration()); System.out.println("============================"); } } } 复制代码
输出的结果
T [sun.reflect.annotation.AnnotatedTypeFactory$AnnotatedTypeBaseImpl@3fee733d] [class java.lang.Object] class com.wizhuo.jdklearning.reflect.dto.SelfHashMap$Entry ============================ V [sun.reflect.annotation.AnnotatedTypeFactory$AnnotatedTypeBaseImpl@5acf9800] [interface java.util.Collection] class com.wizhuo.jdklearning.reflect.dto.SelfHashMap$Entry 复制代码
看到下面这段代码,简单的意思就是从redis 获取字符串,然后转换为指定的泛型的类。大家可以留意到这里创建了个TypeReference 匿名类 注意后面是有带{}的,所以是实例化一个匿名内部类(这是重点中的重点,一切的魔术从这里开始),而不是TypeReference 这个类的实例
List<ResourceEntity> resources = redisAdapter.get(BaseConstant.TENANT_CODE_SYSTEM, CacheKey.KEY_ALL_RESOURCE, new TypeReference<List<ResourceEntity>>() { }); 复制代码
点进去看看这个源码
protected final Type type; /** *注意这里protected ,也就意味着我们创建的时候只能继承这个类成为他的子类,毕竟我们的类 * 不可能和阿里巴巴的fastjson 在同一个包目录下 * * 一般我们都是创建一个匿名内部类来成为他的子类,然后泛型中传进我们想要转化的最终泛型 * 例如上面的代码new TypeReference<List<ResourceEntity>>() {} List<ResourceEntity> 是我们想要转化的类型 * * */ protected TypeReference(){ //这里是获取父类的泛型,由于jdk 不支持获取自己的泛型,这里巧妙的通过继承这个类,变成获取父类的泛型来解决 Type superClass = getClass().getGenericSuperclass(); //这里返回泛型的实际类型,就是 List<ResourceEntity> type = ((ParameterizedType) superClass).getActualTypeArguments()[0]; } 复制代码
如果你觉得这篇内容对你挺有启发,我想邀请你帮我2个小忙: