1. 程式人生 > >Java進階 四 Java反射TypeToken解決泛型執行時型別擦除問題

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,也就是認為stringListintList的型別是一樣的。這就是所謂的泛型型別擦除。執行時我們不知道泛型型別的型別引數是什麼了。

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 指定的型別,並且考慮泛型引數,返回trueList<? extends Number>assignable from List,但List沒有.

getTypes()

返回一個Set,包含了這個所有介面,子類和類是這個型別的類。返回的Set同樣提供了classes()interfaces()方法允許你只瀏覽超類和介面類。

isArray()

檢查某個型別是不是陣列,甚至是<? extends A[]>

getComponentType()

返回元件型別陣列。

 

 

Gson的基本使用就是這麼多,至於annotation方面可以參考gson的官方文件,希望能對初學java和gson的同學有所幫助。

再分享一下我老師大神的人工智慧教程吧。零基礎!通俗易懂!風趣幽默!希望你也加入到我們人工智慧的隊伍中來!http://www.captainbed.net