<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Rising Sun

      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      148 隨筆 :: 0 文章 :: 22 評論 :: 0 Trackbacks

    最近在使用Google的Gson包進(jìn)行Json和Java對象之間的轉(zhuǎn)化,對于包含泛型的類的序列化和反序列化Gson也提供了很好的支持,感覺有點(diǎn)意思,就花時間研究了一下。

    由于Java泛型的實(shí)現(xiàn)機(jī)制,使用了泛型的代碼在運(yùn)行期間相關(guān)的泛型參數(shù)的類型會被擦除,我們無法在運(yùn)行期間獲知泛型參數(shù)的具體類型(所有的泛型類型在運(yùn)行時都是Object類型)。

    但是有的時候,我們確實(shí)需要獲知泛型參數(shù)的類型,比如將使用了泛型的Java代碼序列化或者反序列化的時候,這個時候問題就變得比較棘手。

    1
    2
    3
    4
    5
    6
    7
    8
    class Foo<T> {
      T value;
    }
    Gson gson = new Gson();
    Foo<Bar> foo = new Foo<Bar>();
    gson.toJson(foo); // May not serialize foo.value correctly
     
    gson.fromJson(json, foo.getClass()); // Fails to deserialize foo.value as Bar

     

    對于上面的類Foo<T>,由于在運(yùn)行期間無法得知T的具體類型,對這個類的對象進(jìn)行序列化和反序列化都不能正常進(jìn)行。Gson通過借助TypeToken類來解決這個問題。

    1
    2
    3
    4
    5
    6
    7
    8
    TestGeneric<String> t = new TestGeneric<String>();
      t.setValue("Alo");
      Type type = new TypeToken<TestGeneric<String>>(){}.getType();
       
      String gStr = GsonUtils.gson.toJson(t,type);
      System.out.println(gStr);
      TestGeneric t1 = GsonUtils.gson.fromJson(gStr, type);
      System.out.println(t1.getValue());

     

    TypeToken的使用非常簡單,如上面的代碼,只要將需要獲取類型的泛型類作為TypeToken的泛型參數(shù)構(gòu)造一個匿名的子類,就可以通過getType()方法獲取到我們使用的泛型類的泛型參數(shù)類型。

    下面來簡單分析一下原理。

    要獲取泛型參數(shù)的類型,一般的做法是在使用了泛型的類的構(gòu)造函數(shù)中顯示地傳入泛型類的Class類型作為這個泛型類的私有屬性,它保存了泛型類的類型信息。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public class Foo<T>{
      
     public Class<T> kind;
      
     public Foo(Class<T> clazz){
      this.kind = clazz;
     }
      
     public T[] getInstance(){
      return (T[])Array.newInstance(kind, 5);
     }
      
     public static void main(String[] args){
      Foo<String> foo = new Foo(String.class);
      String[] strArray = foo.getInstance();
     }
     
    }

     

    這種方法雖然能解決問題,但是每次都要傳入一個Class類參數(shù),顯得比較麻煩。Gson庫里面對于這個問題采用了了另一種解決辦法。

    同樣是為了獲取Class的類型,可以通過另一種方式實(shí)現(xiàn):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public abstract class Foo<T>{
      
     Class<T> type;
      
     public Foo(){
      this.type = (Class<T>) getClass();
     }
     
            public static void main(String[] args) {
       
      Foo<String> foo = new Foo<String>(){};
      Class mySuperClass = foo.getClass();
     
     }
      
    }

     

    聲明一個抽象的父類Foo,匿名子類將泛型類作為Foo的泛型參數(shù)傳入構(gòu)造一個實(shí)例,再調(diào)用getClass方法獲得這個子類的Class類型。

    這里雖然通過另一種方式獲得了匿名子類的Class類型,但是并沒有直接將泛型參數(shù)T的Class類型傳進(jìn)來,那又是如何獲得泛型參數(shù)的類型的呢, 這要依賴Java的Class字節(jié)碼中存儲的泛型參數(shù)信息。Java的泛型機(jī)制雖然在運(yùn)行期間泛型類和非泛型類都相同,但是在編譯java源代碼成 class文件中還是保存了泛型相關(guān)的信息,這些信息被保存在class字節(jié)碼常量池中,使用了泛型的代碼處會生成一個signature簽名字段,通過 簽名signature字段指明這個常量池的地址。

    關(guān)于class文件中存儲泛型參數(shù)類型的具體的詳細(xì)的知識可以參考這里:http://stackoverflow.com/questions/937933/where-are-generic-types-stored-in-java-class-files

    JDK里面提供了方法去讀取這些泛型信息的方法,再借助反射,就可以獲得泛型參數(shù)的具體類型。同樣是對于第一段代碼中的foo對象,通過下面的代碼可以得到foo<T>中的T的類型:

    1
    2
    3
    Type mySuperClass = foo.getClass().getGenericSuperclass();
      Type type = ((ParameterizedType)mySuperClass).getActualTypeArguments()[0];
    System.out.println(type);

     

    運(yùn)行結(jié)果是class java.lang.String。

    分析一下這段代碼,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,對于數(shù) 組class則是返回Object.class。ParameterizedType是表示帶有泛型參數(shù)的類型的Java類型,JDK1.5引入了泛型之 后,Java中所有的Class都實(shí)現(xiàn)了Type接口,ParameterizedType則是繼承了Type接口,所有包含泛型的Class類都會實(shí)現(xiàn) 這個接口。

    實(shí)際運(yùn)用中還要考慮比較多的情況,比如獲得泛型參數(shù)的個數(shù)避免數(shù)組越界等,具體可以參看Gson中的TypeToken類及ParameterizedTypeImpl類的代碼。

    posted on 2012-08-01 16:26 brock 閱讀(42680) 評論(6)  編輯  收藏

    評論

    # re: Gson通過借助TypeToken獲取泛型參數(shù)的類型的方法[未登錄] 2013-01-17 22:38 tao
    哥們,你這文章我看不太明白,你這個調(diào)用怎么調(diào)用可以返回泛型,能不能組織一下弄出一個實(shí)例,謝謝  回復(fù)  更多評論
      

    # re: Gson通過借助TypeToken獲取泛型參數(shù)的類型的方法[未登錄] 2013-01-21 14:03 brock
    */
    @SuppressWarnings("unchecked")
    public static <T> T fromJson(String json, TypeToken<T> token, String datePattern) {
    if (StringUtils.isEmpty(json)) {
    return null;
    }
    GsonBuilder builder = new GsonBuilder();
    if (StringUtils.isEmpty(datePattern)) {
    datePattern = DEFAULT_DATE_PATTERN;
    }
    builder.setDateFormat(datePattern);

    Gson gson = builder.create();
    try {
    return (T) gson.fromJson(json, token.getType());
    } catch (Exception ex) {
    ex.printStackTrace();
    log.error(json + " 無法轉(zhuǎn)換為 " + token.getRawType().getName() + " 對象!", ex);
    return null;
    }
    }  回復(fù)  更多評論
      

    # re: Gson通過借助TypeToken獲取泛型參數(shù)的類型的方法 2013-04-08 09:45 發(fā)生大幅
    123  回復(fù)  更多評論
      

    # re: Gson通過借助TypeToken獲取泛型參數(shù)的類型的方法[未登錄] 2014-04-04 11:06 123
    共顫動是SB  回復(fù)  更多評論
      

    # re: Gson通過借助TypeToken獲取泛型參數(shù)的類型的方法 2014-12-11 15:14 yueguangxuanyuan
    Foo<String> foo = new Foo<String>() {
    };
    Class mySuperClasses = foo.getClass();
    System.out.println(mySuperClasses.getSimpleName());

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

    ArrayList<Integer> A = new ArrayList<Integer>();
    mySuperClass = A.getClass().getGenericSuperclass();
    type = ((ParameterizedType) mySuperClass).getActualTypeArguments()[0];
    System.out.println(type);
    System.out.println(((ParameterizedType)A.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);


    運(yùn)行結(jié)果是

    class java.lang.String
    E
    E
    這個和博客主說的有點(diǎn)出入 能幫我解釋一下么  回復(fù)  更多評論
      

    # re: Gson通過借助TypeToken獲取泛型參數(shù)的類型的方法 2014-12-11 17:37 yueguangxuanyuan
    博主如果解決了樓上的問題 請聯(lián)系我 萬分感謝 聯(lián)系方式QQ 474233979  回復(fù)  更多評論
      


    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 最近的中文字幕大全免费8| 无码少妇精品一区二区免费动态 | 一级毛片在线免费看| 亚洲av手机在线观看| 337P日本欧洲亚洲大胆精品 | 日韩亚洲国产高清免费视频| 免费能直接在线观看黄的视频| 100000免费啪啪18免进| 亚洲成色www久久网站夜月| 182tv免费视频在线观看| 国产亚洲一区二区三区在线观看| 亚洲大香伊人蕉在人依线| 91精品免费在线观看| 亚洲国产精品久久人人爱| 成年黄网站色大免费全看| 色婷五月综激情亚洲综合| 在线观看人成视频免费| 337P日本欧洲亚洲大胆精品| 亚洲精品无码99在线观看 | 亚洲GV天堂无码男同在线观看| 日本精品久久久久久久久免费| 6080午夜一级毛片免费看6080夜福利| 免费人成在线观看播放国产 | 亚洲Av无码乱码在线znlu| 搜日本一区二区三区免费高清视频 | 日韩在线视频播放免费视频完整版| 91免费国产精品| 亚洲sss综合天堂久久久| 日日AV拍夜夜添久久免费| 国产精品黄页免费高清在线观看| 免费鲁丝片一级在线观看| 产传媒61国产免费| 亚洲福利电影一区二区?| 啦啦啦手机完整免费高清观看| 亚洲剧情在线观看| 亚洲电影日韩精品| 久久久久高潮毛片免费全部播放 | 国产乱弄免费视频| 波多野结衣免费一区视频| 久久久久精品国产亚洲AV无码| 日本一卡精品视频免费|