Java進階 四 Java反射TypeToken解決泛型執行時型別擦除問題
在開發時,遇到了下面這條語句,不懂,然習之。
private List<MyZhuiHaoDetailModel> listLottery = new ArrayList<MyZhuiHaoDetailModel>();
Gson gson=new Gson();
JSONObject object=new JSONObject(callbackValue);
listLottery = gson.fromJson(object.getString("lists"
new TypeToken<List<MyZhuiHaoDetailModel>>() {
}.getType());
GSON提供了 TypeToken 這個類來幫助我們捕獲(capture)像List<MyZhuiHaoDetailModel>這樣的泛型資訊。上文建立了一個匿名內部類,這樣,Java編譯器就會把泛型資訊編譯到這個匿名內部類裡,然後在執行時就可以被 getType()方法用反射API提取到。
下面來看看gson的反序列化,Gson提供了fromJson()方法來實現從Json相關物件到java實體的方法。
在日常應用中,我們一般都會碰到兩種情況,轉成單一實體物件和轉換成物件列表或者其他結構。
先來看第一種:
比如json字串為:{"name":"name0","age":0}
程式碼:
Person person = gson.fromJson(str, Person.class);
提供兩個引數,分別是json字串以及需要轉換物件的型別。
第二種,轉換成列表型別:
程式碼:
List<Person> ps = gson.fromJson(str, new TypeToken<List<Person>>(){}.getType());
for(int i = 0; i < ps.size() ; i++)
{
Person p = ps.get(i);
System.out.println(p.toString());
}
可以看到上面的程式碼使用了TypeToken,它是gson提供的資料型別轉換器,可以支援各種資料集合型別轉換。
經過比較,gson和其他現有java json類庫最大的不同是gson需要序列化的實體類不需要使用annotation來標識需要序列化得欄位,同時gson又可以通過使用annotation來靈活配置需要序列化的欄位。
另外,java反射包中的TypeToken類是用來解決java執行時泛型型別被擦除的問題的,有點不好理解,我們通過一個例子來認識什麼是泛型的執行時型別擦除。
ArrayList<String> stringList = Lists.newArrayList();
ArrayList<Integer> intList = Lists.newArrayList();
System.out.println("intList type is " + intList.getClass());
System.out.println("stringList type is " + stringList.getClass());
System.out.println(stringList.getClass().isAssignableFrom(intList.getClass()));
上面的程式碼我們聲明瞭兩個泛型的ArrayList型別,一個泛型的型別引數是String,另外一個是Integer;然後我們輸出了兩個泛型的Class,並輸出兩個list的型別是否是同一個list。我們看下輸出的結果:
intList type is class java.util.ArrayListstringList type is class java.util.ArrayListtrue
前兩個輸出都是java.util.ArrayList,而第三個輸出竟然是true,也就是認為stringList和intList的型別是一樣的。這就是所謂的泛型型別擦除。執行時我們不知道泛型型別的型別引數是什麼了。
TypeToken可以解決這個問題,請看下面程式碼:
TypeToken<ArrayList<String>> typeToken = new TypeToken<ArrayList<String>>() {}; TypeToken<?> genericTypeToken = typeToken.resolveType(ArrayList.class.getTypeParameters()[0]); System.out.println(genericTypeToken.getType());
注意上面第一行程式碼使用了一個空的匿名類。第二行使用了resolveType方法解析出泛型型別,第三行程式碼打印出泛型型別,輸出是:
class java.lang.String
可以看出TypeToken解析出了泛型引數的具體型別。
TypeToken的方法列表如下:
方法 |
描述 |
getType() |
獲得包裝的java.lang.reflect.Type. |
getRawType() |
返回大家熟知的執行時類 |
getSubtype(Class<?>) |
返回那些有特定原始類的子型別。舉個例子,如果這有一個Iterable並且引數是List.class,那麼返回將是List。 |
getSupertype(Class<?>) |
產生這個型別的超類,這個超類是指定的原始型別。舉個例子,如果這是一個Set並且引數是Iterable.class,結果將會是Iterable。 |
isAssignableFrom(type) |
如果這個型別是 assignable from 指定的型別,並且考慮泛型引數,返回true。List<? extends Number>是assignable from List,但List沒有. |
getTypes() |
返回一個Set,包含了這個所有介面,子類和類是這個型別的類。返回的Set同樣提供了classes()和interfaces()方法允許你只瀏覽超類和介面類。 |
isArray() |
檢查某個型別是不是陣列,甚至是<? extends A[]>。 |
getComponentType() |
返回元件型別陣列。 |
Gson的基本使用就是這麼多,至於annotation方面可以參考gson的官方文件,希望能對初學java和gson的同學有所幫助。
再分享一下我老師大神的人工智慧教程吧。零基礎!通俗易懂!風趣幽默!希望你也加入到我們人工智慧的隊伍中來!http://www.captainbed.net