2015-05-02 5 views
14

Я понимаю, что в Java, вопреки, например, C# generics - это функция времени компиляции и удаляется с помощью стирания типа. Итак, как работает Gson's TypeToken? Как он получает общий тип объекта?Как работает Gson TypeToken?

ответ

18

It's a trick!

From §4.6 of the JLS (курсив мой):

Тип стирание является отображением типов (включая, возможно, параметризованные тип и переменный тип) до типов (которые никогда не параметризованные типов или переменного типа). Будем писать | T | для стирания типа Т. Отображение стирания определяется следующим образом:

Стирание параметризованного типа (§4.5) G является | G |.

Стирание вложенного типа T.C является | T | .C.

Стирание типа массива T [] является | T | [].

Стирание переменной типа (§4.4) является стиранием его левого края.

Стирание любого другого типа - это сам тип.

Поэтому, если вы объявляете класс с анонимным подклассом, он сохраняет его параметризованный тип; он не стирается. Поэтому, рассмотрим следующий код:

import java.lang.reflect.ParameterizedType; 
import java.util.Arrays; 
import java.util.HashMap; 

public class Erasure<T> 
{ 
    public static void main(String...strings) { 
     Class<?> foo = new Erasure<HashMap<Integer, String>>() {}.getClass(); 
     ParameterizedType t = (ParameterizedType) foo.getGenericSuperclass(); 
     System.out.println(t.getOwnerType()); 
     System.out.println(t.getRawType()); 
     System.out.println(Arrays.toString(t.getActualTypeArguments())); 
    } 
} 

Это выходы:

null 
class Erasure 
[java.util.HashMap<java.lang.Integer, java.lang.String>] 

Обратите внимание, что вы получите ClassCastException если вы не объявить класс анонимно, из-за стирания; суперкласс не будет параметризованным типом, это будет Object.

4

Стирание типа Java применяется к отдельным объектам, а не к классам, полям или методам. TypeToken использует анонимный класс, чтобы обеспечить сохранение общей информации типа, а не просто создание объекта.