Gson TypeToken 是如何工作的?

How does Gson TypeToken work?

我知道在 Java 中相反,例如,C# 泛型是编译时特性,并通过类型擦除被删除。那么,Gson 的 TypeToken 到底是如何工作的呢?它是如何获取对象的通用类型的?

Java 的类型擦除适用于单个对象,不适用于 classes 或字段或方法。 TypeToken 使用匿名 class 来确保它保留通用类型信息,而不是仅仅创建一个对象。

From §4.6 of the JLS(强调我的):

Type erasure is a mapping from types (possibly including parameterized types and type variables) to types (that are never parameterized types or type variables). We write |T| for the erasure of type T. The erasure mapping is defined as follows:

The erasure of a parameterized type (§4.5) G is |G|.

The erasure of a nested type T.C is |T|.C.

The erasure of an array type T[] is |T|[].

The erasure of a type variable (§4.4) is the erasure of its leftmost bound.

The erasure of every other type is the type itself.

因此,如果您使用自身的匿名子 class 声明一个 class,它会保持其参数化类型;它没有被删除。因此,请考虑以下代码:

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>]

请注意,如果您没有匿名声明 class,您会得到一个 ClassCastException,因为擦除; superclass 不会是参数化类型,它会是 Object.

Gson TypeToken 使用 Neal Gafter 的 super type tokens pattern. this pattern is based on the Class#getGenericSuperclass() 方法,来自文档

Returns the Type representing the direct superclass of the entity (class, interface, primitive type or void) represented by this Class. If the superclass is a parameterized type, the Type object returned must accurately reflect the actual type parameters used in the source code.

这实质上意味着如果你有一个 class 扩展一个参数化的 class,那么你可以获得实际类型参数到 super class as

((ParameterizedType)myClassObj.getGenericSuperClass()).getActualTypeArguments()

所以当你在 Gson 中创建类型标记时

Type someTypeToken = new TypeToken<Collection<Integer>>(){};

// This essentially is same as defining
class AnonClass extends TypeToken<Collection<Integer>>{}

现在您可以很容易地获取 Type 参数到上面指定的超类型 (TypeToken)。