java 泛型详解+ 阿里fastjson 源码中的巧妙运用

引言

在讲阿里fastjson 以前,先讲下泛型的一些基础知识和在反射中如何获取泛型,以为本身已经掌握的能够直接经过目录跳到最后查看java

泛型类

泛型类的定义只要在申明类的时候,在类名后面直接加上< E>,中的E能够是任意的字母,也能够多个,多个用逗号隔开就能够。示例代码以下面试

public class SelfList<E> {}
复制代码

泛型类中的实际类型的推断

那么何时肯定这个E 的具体类型呢?实际上是在new 一个对象的时候指定的,请看下面代码redis

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);
    }

}

复制代码

泛型接口

泛型接口和类的使用方式同样json

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;
    }
复制代码
  1. 返回值和public 之间的< T> 是泛型方法的必要条件,而且这个和类的定义的泛型E 是能够同名(通常设置不一样名),而且他们之间是独立的。
  2. < T> 能够多个,多个用逗号隔开,列如 <T,V>
  3. 返回值不必定是T,能够是任意的类型,如Long
  4. 方法中的参数也不必定是T,能够是任意的类型,如Long。只是泛型方法通常返回值类型和参数有其中一个是定义的泛型(全是具体类型就没意义了)
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);
    }
复制代码

泛型方法中的实际泛型的推断

那么泛型方法是怎么肯定这个具体类型的呢? 主要思想是在调用该泛型方法传进去的参数类型和返回值类型来肯定具体类型的bash

  1. 泛型变量在参数列表中只出现一次,调用该方法时根据传进行的实参类型来肯定
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
复制代码
  1. 当参数列表中有多个参数使用了相同的泛型变量,返回值类型也使用了该变量,那么返回值类型由他们的公共父类来决定最终的泛型类型
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);
    }
复制代码

注意上面的输出还会是ui

I am Integer
复制代码

由于根据第一条规则,传进去的是什么类型就是什么类型,可是返回值类型候须要根据第二条规则来肯定spa

反射中的泛型使用

上面说的都是在编译以前就能够肯定的泛型。你们知道,泛型运行的时候实际上是会被擦除的。不过不要紧,仍是提供给咱们经过反射的方式来获取。首先我来认识下java中的泛型类型继承结构

这里主要讲平时运用最多的三个类,其余还有一些GenericArrayType 之类的就不讲了,你们按着我这个分析的思路去看下就能够

ParameterizedType 源码

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();
}
复制代码

ParameterizedType 测试验证

定义一个有内部类的类

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
复制代码

TypeVariable 源码

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
复制代码

阿里fastjson 泛型的巧妙运用

看到下面这段代码,简单的意思就是从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个小忙:

  1. 点赞,让更多的人也能看到这篇内容(收藏不点赞,都是耍流氓 -_-)
  2. 关注公众号「面试bat」,不按期分享原创知识,原创不易,请多支持(里面还提供刷题小程序哦)。

相关文章
相关标签/搜索