Gson TypeToken 原理解析

直男碼農傲嬌求贊求評論~^_^~

假設有個User類,我們想用Gson將一個字符串解析成User類,那麼可以像下面這樣,比較簡單:

Gson gson = new Gson();
User user = gson.fromJson("user對象json字符串",User.class)

但是如果是一個User數組的字符串呢,我們希望解析成List<User> 類型的一個數組

這個List<User>不能直接.class,我們可以用下面這個方法

public <T> T fromJson(String json, Type typeOfT){
}

然後這裏的 Type typeOfT,即List<User> 的Type 如何獲取呢?

可以這樣:(利用Gson庫中的TypeToken類)就可以獲取到List<User> 的Type,進而完成解析

Type type = new TypeToken<List<User>>(){}.getType();

那麼TypeToken內部究竟是如何做的呢?下面請看源碼

public class TypeToken<T> {
  final Class<? super T> rawType;
  final Type type;
  final int hashCode;

/**
   * Gets underlying {@code Type} instance.
   */
  public final Type getType() {
    return type;
  }

//protected 修飾符不能在外部直接new對象

  /**
   * Constructs a new type literal. Derives represented class from type
   * parameter.
   *
   * <p>Clients create an empty anonymous subclass. Doing so embeds the type
   * parameter in the anonymous class's type hierarchy so we can reconstitute it
   * at runtime despite erasure.
   */
  @SuppressWarnings("unchecked")
  protected TypeToken() {
    this.type = getSuperclassTypeParameter(getClass());
    this.rawType = (Class<? super T>) $Gson$Types.getRawType(type);
    this.hashCode = type.hashCode();
  }
//默認修飾符 不能在外部直接new對象
  /**
   * Unsafe. Constructs a type literal manually.
   */
  @SuppressWarnings("unchecked")
  TypeToken(Type type) {
    this.type = $Gson$Types.canonicalize($Gson$Preconditions.checkNotNull(type));
    this.rawType = (Class<? super T>) $Gson$Types.getRawType(this.type);
    this.hashCode = this.type.hashCode();
  }

  /**
   * Returns the type from super class's type parameter in {@link $Gson$Types#canonicalize
   * canonical form}.
   */
  static Type getSuperclassTypeParameter(Class<?> subclass) {
//注意注意,這句話比較重要,這個是獲取父類的帶泛型的Class對象
//因爲構造方法已經不能直接用於在外部直接new對象,所以在外部只能通過子類的方式來構造對象
//而匿名內部類就是一個對該類的繼承方式
//通過匿名內部類的方式得到一個對象,通過該對象getClass.getGenericSuperclass()方法
//獲取到父類的帶泛型的Class對象,就是TypeToken 本身了
    Type superclass = subclass.getGenericSuperclass();
    if (superclass instanceof Class) {
      throw new RuntimeException("Missing type parameter.");
    }
//因爲TypeToken上定義了泛型,在外部使用時傳了具體的類型,
//獲取的genericSuperclass就是ParameterizedType
//進而通過ParameterizedType的getActualTypeArguments方法獲取實際的泛型數組
//因爲TypeToken類上只定義了一個泛型參數,所以這裏獲取的Type[]大小就是1了
//直接[0],就獲取到了傳入的實際類型Type,即傳入的List<User>
    ParameterizedType parameterized = (ParameterizedType) superclass;
//canonicalize 看字面是規範化的意思,內部主要是Gson將Java jdk中Type的各個實現類轉換成了Gson自
//己對Type的各個實現類 (測試發現不調用這個方法也能對數組類型的字符串也能解析成功)
    return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
  }
//省略代碼。。。。
}

 關於Type 和 ParameterizedType 

Type 有 5個子類/接口,其中一個就是 ParameterizedType 

而 ParameterizedType 裏有三個方法

直接舉例,如果是List<User> 那麼Type[] 就是[User],
如果是Map<Integer,String>,那麼Type[] 就是[Integer,String]
如果是HashMap<Integer,List<User>>,那麼Type[]就是[Integer,List<User>]
總之,就是獲取最外層<>裏面的內容

Type[] getActualTypeArguments();

舉例:如果是List<User> 那麼Type 就是List,
如果是Map<Integer,String>,那麼Type 就是Map
如果是HashMap<Integer,List<User>>,那麼Type[]就是HashMap
 

Type getRawType();
Type getOwnerType();

關於Type更多內容可以參考

https://www.jianshu.com/p/e8eeff12c306

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章