Gson在Json解析中使用廣泛, 常用的數(shù)據(jù)類型都可以解析, 特殊的可以自定義Adapter解析. 在解析大量具有某些相同結(jié)構(gòu)的數(shù)據(jù)上,我們總想復(fù)用已有的類型, 為了復(fù)用通??梢允褂美^承和泛型. 比如服務(wù)端返回的json都有類似結(jié)構(gòu):
{"code":200,
"message":"success",
"data":"{...}"
}
其中data
對應(yīng)的結(jié)構(gòu)不定, 一種考慮是使用泛型:
public class Response{public T data;//簡化數(shù)據(jù), 省略了其他字段
}
于是在做json解析是很可能會這樣使用:
String json = "{\"data\":\"data from server\"}";
Type type = new TypeToken>(){}.getType();
Responseresult = new Gson().fromJson(json, type);
這個TypeToken
是如何和類型Response
產(chǎn)生關(guān)系,又是怎樣存儲泛型信息的? 首先需要明確Type是什么.
這里的Type指java.lang.reflect.Type, 是Java中所有類型的公共高級接口, 代表了Java中的所有類型. Type體系中類型的包括:數(shù)組類型(GenericArrayType)、參數(shù)化類型(ParameterizedType)、類型變量(TypeVariable)、通配符類型(WildcardType)、原始類型(Class)、基本類型(Class), 以上這些類型都實現(xiàn)Type接口.
參數(shù)化類型,就是我們平常所用到的泛型List、Map;
數(shù)組類型,并不是我們工作中所使用的數(shù)組String[] 、byte[],而是帶有泛型的數(shù)組,即T[] ;
通配符類型, 指的是>, extends T>等等
原始類型, 不僅僅包含我們平常所指的類,還包括枚舉、數(shù)組、注解等;
基本類型, 也就是我們所說的java的基本類型,即int,float,double等
本文的重點在于參數(shù)化類型(ParameterizedType).
public interface ParameterizedType extends Type {// 返回確切的泛型參數(shù), 如Map返回[String, Integer]
Type[] getActualTypeArguments();
//返回當前class或interface聲明的類型, 如List>返回List
Type getRawType();
//返回所屬類型. 如,當前類型為O.I, 則返回O. 頂級類型將返回null
Type getOwnerType();
}
獲取類型的困惑對于普通的類想要獲取類型簡單調(diào)用.class
或者getClass()
方法即可,
ClassstringClass = String.class;
Class>stringClass2 = "hello".getClass();
但對于泛型你不能這樣做,
Response.class //不能通過編譯
Response.class //只能這樣獲取類型, 但無法知道元素的類型
那么在做json解析時我們?nèi)绻_實是需要讓Gson解析成Response
, 可以像上文的方式處理.
先看一段代碼:
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public abstract class MyTypeToken{private final Type type;
public MyTypeToken() {Type genericSuperclass = getClass().getGenericSuperclass();
if(genericSuperclass instanceof Class){throw new RuntimeException("Missing type parameter.");
}
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
Type[] typeArguments = parameterizedType.getActualTypeArguments();
type = typeArguments[0];
}
public Type getType() {return type;
}
}
MyTypeToken聲明為抽象類, 使用時需要對其進行實例化, 實例化過程可以分解如下:
MyTypeTokensToken = new MyTypeToken(){};
相當于
class MyTypeToken$0 extends MyTypeToken{}
MyTypeTokensToken = new MyTypeToken$0();
這樣分解的目的在于明確sToken
的類型是MyTypeToken$0(匿名的)
,父類型是MyTypeToken
而不是MyTypeToken
.
getClass().getSuperclass()
獲取的是當前對象所屬的類型的父類型. 注意到抽象類實例化時需要給具體的泛型類, 如果沒有提供則使用Object(但此時使用的已不是泛型類了, 而是原始類型, 也就是擦除泛型后的類型)代替泛型參數(shù). 因此如果像上面那樣實例化, 那么getClass().getGenericSuperclass()
得到的將是類型參數(shù)實例化后的父類型MyTypeToken
, 泛型信息保留下來了. 如果不用泛型得到的是MyTypeToken
, 是原始類型.
得到泛型參數(shù)實例化后的類型,getActualTypeArguments()
返回的是確切的類型參數(shù)數(shù)組, 此處MyTypeToken只有一個類型參數(shù), 返回的是數(shù)組[String.class]
.
至此, 通過new MyTypeToken>() {}.getType()
得到的正是表示Response
的類型, 將該類型應(yīng)用在Gson在解析Response
上將獲得和TypeToken
一致的效果(當然就這么點代碼功能肯定是比不上了).
探究TypeToken的目的其實為了解決以下問題而總結(jié)的.
//封裝getType()操作
public class TokenUtil{public staticType getType(){return new MyTypeToken() {}.getType();
}
}
// 本意在于獲取Response的類型, 但是new MyTypeToken() {}時已經(jīng)實現(xiàn)了
// 抽象類, 相當于創(chuàng)建一個子類 class MyTypeToken$0extends MyTypeToken{},
// 實例化時雖然傳入的是Response, 但.getGenericSuperclass()=MyTypeToken$0// 于是getType()返回的只是泛型參數(shù)類型E, 正真解析是按照Gson流程選擇Map或者List
Type type = TokenUtil.>getType();
// fromJson返回Map或者List, ClassCastException!
Responseo = new Gson().fromJson(json, type);
總結(jié)Gson解析時TypeToken
的泛型參數(shù)只能使用時傳入確切的類型才能獲取正確的Type, 這也是TypeToken
設(shè)計成抽象類的巧妙之處和原因(改為只有protected構(gòu)造方法的普通類原理一樣). 一旦將TypeToken
改成普通類, 根據(jù)上面的分析, 一切類型信息都被擦除, Gson解析將得不到預(yù)期的類型.
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧