Я понимаю, что в Java, вопреки, например, C# generics - это функция времени компиляции и удаляется с помощью стирания типа. Итак, как работает Gson's TypeToken
? Как он получает общий тип объекта?Как работает Gson TypeToken?
ответ
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
.
Стирание типа Java применяется к отдельным объектам, а не к классам, полям или методам. TypeToken использует анонимный класс, чтобы обеспечить сохранение общей информации типа, а не просто создание объекта.