<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          掌握 Java-TypeToken 原理及泛型擦除

          共 3403字,需瀏覽 7分鐘

           ·

          2020-12-26 13:15

          點擊上方藍色“程序猿DD”,選擇“設為星標”

          回復“資源”獲取獨家整理的學習資料!

          作者 |?Alben

          來源 |?http://r6d.cn/UeXQ

          概要

          借助對TypeToken原理的分析,加強對泛型擦除的理解,使得我們能夠知道什么時候,通過什么方式可以獲取到泛型的類型。

          泛型擦除

          眾所周知,Java的泛型只在編譯時有效,到了運行時這個泛型類型就會被擦除掉,即ListList在運行時其實都是List類型。

          為什么選擇這種實現機制?不擦除不行么?在Java誕生10年后,才想實現類似于C++模板的概念,即泛型。Java的類庫是Java生態(tài)中非常寶貴的財富,必須保證向后兼容(即現有的代碼和類文件依舊合法)和遷移兼容(泛化的代碼和非泛化的代碼可互相調用)基于上面這兩個背景和考慮,Java設計者采取了“類型擦除”這種折中的實現方式。

          同時正正有這個這么“坑”的機制,令到我們無法在運行期間隨心所欲的獲取到泛型參數的具體類型。

          TypeToken

          使用

          使用過Gson的同學都知道在反序列化時需要定義一個TypeToken類型,像這樣

          private?Type?type?=?new?TypeToken>>(){}.getType();

          //調用fromJson方法時把type傳過去,如果type的類型和json保持一致,則可以反序列化出來
          gson.fromJson(json,?type);

          三個問題

          1. 為什么要用TypeToken來定義反序列化的類型?正如上面說的,如果直接把List>的類型傳過去,但是因為運行時泛型被擦除了,所以得到的其實是List,那么后面的Gson就不知道要轉成Map類型了,這時Gson會默認轉成LinkedTreeMap類型。

          2. 為什么帶有大括號{}?這個大括號就是精髓所在。大家都知道,在Java語法中,在這個語境,{}是用來定義匿名類,這個匿名類是繼承了TypeToken類,它是TypeToken的子類。

          3. 為什么要通過子類來獲取泛型的類型?這是TypeToken能夠獲取到泛型類型的關鍵,這是一個巧妙的方法。這個想法是這樣子的,既然像List這樣中的泛型會被擦除掉,那么我用一個子類SubList extends List這樣的話,在JVM內部中會不會把父類泛型的類型給保存下來呢?我這個子類需要繼承的父類的泛型都是已經確定了的呀,果然,JVM是有保存這部分信息的,它是保存在子類的Class信息中,具體看:https://stackoverflow.com/questions/937933/where-are-generic-types-stored-in-java-class-files 那么我們怎么獲取這部分信息呢?還好,Java有提供API出來:

          4. ???Type?mySuperClass?=?foo.getClass().getGenericSuperclass();
            ?????Type?type?=?((ParameterizedType)mySuperClass).getActualTypeArguments()[0];
            ???System.out.println(type);

            分析一下這段代碼,Class類的getGenericSuperClass()方法的注釋是:

            Returns the Type representing the direct superclass of the entity (class, interface, primitive type or void) represented by thisClass. If the superclass is a parameterized type, the Type object returned must accurately reflect the actual type parameters used in the source code. The parameterized type representing the superclass is created if it had not been created before. See the declaration of ParameterizedType for the semantics of the creation process for parameterized types. If thisClass represents either theObject class, an interface, a primitive type, or void, then null is returned. If this object represents an array class then theClass object representing theObject class is returned

            概括來說就是對于帶有泛型的class,返回一個ParameterizedType對象,對于Object、接口和原始類型返回null,對于數 組class則是返回Object.class。ParameterizedType是表示帶有泛型參數的類型的Java類型,JDK1.5引入了泛型之 后,Java中所有的Class都實現了Type接口,ParameterizedType則是繼承了Type接口,所有包含泛型的Class類都會實現 這個接口。

            自己調試一下就知道它返回的是什么了。

            原理

            核心的方法就是剛剛說的那兩句,剩下的就很簡單了。我們看看TypeToken的getType方法

            public?final?Type?getType()?{
            ?//直接返回type
            ????return?type;
            ??}

            看type的初始化

            //注意這里用了protected關鍵字,限制了只有子類才能訪問
            protected?TypeToken()?{
            ????this.type?=?getSuperclassTypeParameter(getClass());
            ????this.rawType?=?(Classsuper?T>)?$Gson$Types.getRawType(type);
            ????this.hashCode?=?type.hashCode();
            ??}
            ??
            ??//getSuperclassTypeParameter方法
            ??//這幾句就是上面的說到
            ??static?Type?getSuperclassTypeParameter(Class?subclass)?{
            ????Type?superclass?=?subclass.getGenericSuperclass();
            ????if?(superclass?instanceof?Class)?{
            ??????throw?new?RuntimeException("Missing?type?parameter.");
            ????}
            ????ParameterizedType?parameterized?=?(ParameterizedType)?superclass;
            ????//這里注意一下,返回的是Gson自定義的,在$Gson$Types里面定義的TypeImpl等,這個類都是繼承Type的。
            ????return?$Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
            ??}

            總結

            在了解原理之后,相信大家都知道怎么去獲取泛型的類型了。

            參考資料

            https://www.cnblogs.com/doudouxiaoye/p/5688629.html

            掃一掃,關注我

            申請加入Java技術學習交流群


            【往期推薦】

            36 張圖梳理 Intellij IDEA 常用設置

            2020-12-23

            13個Mongodb GUI可視化管理工具,總有一款適合你

            2020-12-23

            小宇宙爆發(fā)!Spring Boot 新特性:節(jié)省95%內存占用

            2020-12-22

            超級干貨:你應該知道的那些編程原則!!

            2020-12-22

            不敢相信,居然用Java寫了個“天天酷跑”!

            2020-12-21

            深度內容

            推薦加入


            歡迎加入知識星球,一起探討技術架構,交流技術人生。
            加入方式,長按下方二維碼:
            已在知識星球更新如下:

            素質二連,走一個

            瀏覽 41
            點贊
            評論
            收藏
            分享

            手機掃一掃分享

            分享
            舉報
            評論
            圖片
            表情
            推薦
            點贊
            評論
            收藏
            分享

            手機掃一掃分享

            分享
            舉報
            <kbd id="afajh"><form id="afajh"></form></kbd>
            <strong id="afajh"><dl id="afajh"></dl></strong>
              <del id="afajh"><form id="afajh"></form></del>
                  1. <th id="afajh"><progress id="afajh"></progress></th>
                    <b id="afajh"><abbr id="afajh"></abbr></b>
                      <th id="afajh"><progress id="afajh"></progress></th>
                      内射无码精品 | 神马影音先锋无码视频 | 影音先锋资源你懂的 | 黄页网站在线观看视频 | 欧美在线A片 |