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」,不按期分享原創知識,原創不易,請多支持(裏面還提供刷題小程序哦)。

相關文章
相關標籤/搜索