我知道在Java中,例如,与C#相反,泛型是编译时的特性,可以通过类型擦除来删除。那么,Gson的TypeToken到底是如何工作的呢?它是如何获得对象的泛型类型的呢?
TypeToken
bis0qfac1#
来自JLS的§4.6(重点是我):类型擦除是从类型(可能包括参数化类型和类型变量)到类型(从不是参数化类型或类型变量)的Map。|T形|对于类型T的擦除。擦除Map定义如下:参数化类型(§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。
ClassCastException
Object
5ssjco0h2#
Java的类型擦除应用于单个对象,而不是类、字段或方法。TypeToken使用一个匿名类来确保它保留泛型类型信息,而不仅仅是创建一个对象。
ccrfmcuu3#
Gson TypeToken使用Neal Gaft的super type tokens模式。此模式基于docs中的Class#getGenericSuperclass()方法返回Type,它表示由此类表示得实体(类,接口,基元类型或void)得直接超类.如果超类是参数化类型,则返回得Type对象必须准确反映源代码中使用得实际类型参数.这实质上意味着,如果您有一个扩展参数化类的类,那么您可以将实际类型参数作为
Class#getGenericSuperclass()
Type
((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)。
3条答案
按热度按时间bis0qfac1#
来自JLS的§4.6(重点是我):
类型擦除是从类型(可能包括参数化类型和类型变量)到类型(从不是参数化类型或类型变量)的Map。|T形|对于类型T的擦除。擦除Map定义如下:
参数化类型(§4.5)G的擦除是|G级|。
嵌套类型T. C的擦除是|T形|. C、
数组类型T[]的擦除是|T形|[].
类型变量的擦除(参见4.4节)是其最左边界的擦除。
其他类型的擦除就是类型本身。
因此,如果您声明一个类,它有自己的匿名子类,它会保持它的参数化类型;因此,请考虑以下代码:
这将输出:
请注意,如果您没有匿名声明类,则会得到一个
ClassCastException
,因为存在擦除;超类将不是参数化类型,而是Object
。5ssjco0h2#
Java的类型擦除应用于单个对象,而不是类、字段或方法。TypeToken使用一个匿名类来确保它保留泛型类型信息,而不仅仅是创建一个对象。
ccrfmcuu3#
Gson TypeToken使用Neal Gaft的super type tokens模式。此模式基于docs中的
Class#getGenericSuperclass()
方法返回
Type
,它表示由此类表示得实体(类,接口,基元类型或void)得直接超类.如果超类是参数化类型,则返回得Type
对象必须准确反映源代码中使用得实际类型参数.这实质上意味着,如果您有一个扩展参数化类的类,那么您可以将实际类型参数作为
所以当你在Gson中创建一个类型标记
现在,您可以轻松地将Type参数设置为上面指定的超类型(TypeToken)。