Я понимаю, что в Java, в отличие, например, от дженериков C#, функция времени компиляции и удаляется с помощью стирания типа. Итак, как на самом деле работает TypeToken
от Gson? Как он получает общий тип объекта?
Как работает Gson TypeToken?
Ответы (2)
Из §4.6 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 использует анонимный класс, чтобы гарантировать, что он хранит информацию об универсальном типе, а не просто создает объект.