2017-05-24 80 views
2

我有一些代碼需要多次使用,所以我想把它放在一個方法中。該代碼是:爲什麼使用通用類型的泛型返回方法不正確?

try 
{ 
    //Create a list descriptor for GSON to use 
    Type listType = new TypeToken<ArrayList<MyClass>>(){}.getType(); 

    //Get it out as a list 
    List<MyClass> myClass = gson.fromJson(jsonString, listType); 
} 
catch (Exception e) 
{ 
    e.printStackTrace(); 
} 

我把這個方法,如:

public static <T> List<T> getTypeAsList(String jsonString) 
{ 
    try 
    { 
     Gson gson = new Gson(); 

     //Create a list descriptor for GSON to use 
     Type listType = new TypeToken<ArrayList<T>>(){}.getType(); 

     //Get it out as a list 
     return gson.fromJson(jsonString, listType); 
    } 
    catch (Exception e) 
    { 
     e.printStackTrace(); 
     return null; 
    } 
} 

我調用該方法,如:

util.<MyClass>getTypeAsList(jsonString); 

但是當我這樣做,我得到的錯誤:

com.google.gson.internal.StringMap cannot be cast to MyClass 

爲什麼它沒有得到正確的類型?它在第一個代碼中工作,而不是在通用方法中。

回答

3

類型T被擦除。這意味着通用方法沒有T的類型信息。

通常一個TypeToken用於捕獲這種類型的信息,但它的詳細實例之一,而在你的情況下,你已經知道的一些信息,即認爲你有List一些類型。

所以,你可以創建一個實用方法,來創建一個ParameterizedTypeArrayList爲原料類型,以及任意Type作爲一個類型參數:

public static ParameterizedType listTypeWith(Type t) { 
    Type[] actual = { t }; 
    return new ParameterizedType() { 

     @Override 
     public Type getRawType() { 
      return ArrayList.class; 
     } 

     @Override 
     public Type getOwnerType() { 
      return null; 
     } 

     @Override 
     public Type[] getActualTypeArguments() { 
      return actual; 
     } 
    }; 
} 

然後你可以使用它像這樣:

Gson gson = new Gson(); 

List<MyClass> result = gson.fromJson("[{s:'Hello'}]", listTypeWith(MyClass.class)); 
System.out.println(result); // [MyClass [s=Hello]] 
+0

當文件被編譯時,類型被擦除,所以它在運行時不知道「T」。但它以某種方式推斷'T'爲'StringMap'。你知道爲什麼嗎 ? – SomeDude

+0

@svasa這不是推斷'StringMap',這只是默認值。它得到一個'ParameterizedType',其中的類型參數是非具體的,它將被稱爲'T',而且gson不能使用它。 –

+0

@JornVernee你知道爲什麼類型被刪除?有什麼方法可以防止它被擦除? –

0

發生這種情況是由於編譯時的類型擦除。在編譯一個匿名類將與實際類型ArrayList<MyClass>生成在第一種情況下

new TypeToken<ArrayList<MyClass>>(){} 

-

爲了進一步解釋。在另一方面與普通的調用

實際編譯匿名類將收到ArrayList<Object>爲實際的類型。因此,gson使用默認實現(即StringMap)來反序列化陣列元素

+0

類型擦除處於運行時。 –

+1

不,類型在編譯時被刪除,這就是爲什麼它在運行時不可用。如果它在編譯時沒有被擦除,那麼肯定會有一個選項,在運行時不會擦除它;) – Alexey

+0

@Alexey有沒有辦法在編譯時不擦除它? –

相關問題