直男碼農傲嬌求贊求評論~^_^~
假設有個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