Gson TypeToken 原理解析

本文介绍如何使用Gson库解析JSON字符串为List<User>类型。通过TypeToken类获取List<User>的Type实例,实现数组类型的解析。深入探讨TypeToken的构造方法及Type和ParameterizedType的使用。
摘要由CSDN通过智能技术生成

直男码农傲娇求赞求评论~^_^~

假设有个User类,我们想用Gson将一个字符串解析成User类,那么可以像下面这样,比较简单:

Gson gson = new Gson();
User user = gson.fromJson("user对象json字符串",User.class)

但是如果是一个User数组的字符串呢,我们希望解析成List<User> 类型的一个数组

这个List<User>不能直接.class,我们可以用下面这个方法

public <T> T fromJson(String json, Type typeOfT){
}

然后这里的 Type typeOfT,即List<User> 的Type 如何获取呢?

可以这样:(利用Gson库中的TypeToken类)就可以获取到List<User> 的Type,进而完成解析

Type type = new TypeToken<List<User>>(){}.getType();

那么TypeToken内部究竟是如何做的呢?下面请看源码

public class TypeToken<T> {
  final Class<? super T> rawType;
  final Type type;
  final int hashCode;

/**
   * Gets underlying {@code Type} instance.
   */
  public final Type getType() {
    return type;
  }

//protected 修饰符不能在外部直接new对象

  /**
   * Constructs a new type literal. Derives represented class from type
   * parameter.
   *
   * <p>Clients create an empty anonymous subclass. Doing so embeds the type
   * parameter in the anonymous class's type hierarchy so we can reconstitute it
   * at runtime despite erasure.
   */
  @SuppressWarnings("unchecked")
  protected TypeToken() {
    this.type = getSuperclassTypeParameter(getClass());
    this.rawType = (Class<? super T>) $Gson$Types.getRawType(type);
    this.hashCode = type.hashCode();
  }
//默认修饰符 不能在外部直接new对象
  /**
   * Unsafe. Constructs a type literal manually.
   */
  @SuppressWarnings("unchecked")
  TypeToken(Type type) {
    this.type = $Gson$Types.canonicalize($Gson$Preconditions.checkNotNull(type));
    this.rawType = (Class<? super T>) $Gson$Types.getRawType(this.type);
    this.hashCode = this.type.hashCode();
  }

  /**
   * Returns the type from super class's type parameter in {@link $Gson$Types#canonicalize
   * canonical form}.
   */
  static Type getSuperclassTypeParameter(Class<?> subclass) {
//注意注意,这句话比较重要,这个是获取父类的带泛型的Class对象
//因为构造方法已经不能直接用于在外部直接new对象,所以在外部只能通过子类的方式来构造对象
//而匿名内部类就是一个对该类的继承方式
//通过匿名内部类的方式得到一个对象,通过该对象getClass.getGenericSuperclass()方法
//获取到父类的带泛型的Class对象,就是TypeToken 本身了
    Type superclass = subclass.getGenericSuperclass();
    if (superclass instanceof Class) {
      throw new RuntimeException("Missing type parameter.");
    }
//因为TypeToken上定义了泛型,在外部使用时传了具体的类型,
//获取的genericSuperclass就是ParameterizedType
//进而通过ParameterizedType的getActualTypeArguments方法获取实际的泛型数组
//因为TypeToken类上只定义了一个泛型参数,所以这里获取的Type[]大小就是1了
//直接[0],就获取到了传入的实际类型Type,即传入的List<User>
    ParameterizedType parameterized = (ParameterizedType) superclass;
//canonicalize 看字面是规范化的意思,内部主要是Gson将Java jdk中Type的各个实现类转换成了Gson自
//己对Type的各个实现类 (测试发现不调用这个方法也能对数组类型的字符串也能解析成功)
    return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
  }
//省略代码。。。。
}

 关于Type 和 ParameterizedType 

Type 有 5个子类/接口,其中一个就是 ParameterizedType 

而 ParameterizedType 里有三个方法

直接举例,如果是List<User> 那么Type[] 就是[User],
如果是Map<Integer,String>,那么Type[] 就是[Integer,String]
如果是HashMap<Integer,List<User>>,那么Type[]就是[Integer,List<User>]
总之,就是获取最外层<>里面的内容

Type[] getActualTypeArguments();

举例:如果是List<User> 那么Type 就是List,
如果是Map<Integer,String>,那么Type 就是Map
如果是HashMap<Integer,List<User>>,那么Type[]就是HashMap
 

Type getRawType();
Type getOwnerType();

关于Type更多内容可以参考

https://www.jianshu.com/p/e8eeff12c306

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值