gson源码解析-数组

今天看看数组相关的转换

    private void array() {
        List<User> users = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            User user = new User();
            user.setAge(24+i);
            user.setName("fcl"+i);
            users.add(user);
        }
        Gson gson = new Gson();
        String s = gson.toJson(users);
        Logger.error(TAG, s);
        List<User> users1 = gson.fromJson(s, new TypeToken<List<User>>(){}.getType());
        Logger.error(TAG, "size:"+users1.size());
    }

ArrayList对应的factory是CollectionTypeAdapterFactory,所以接着看他内部类Adapter的write方法即可

    public void write(JsonWriter out, Collection<E> collection) throws IOException {
      if (collection == null) {
        out.nullValue();
        return;
      }

      out.beginArray();
      for (E element : collection) {
        elementTypeAdapter.write(out, element);
      }
      out.endArray();
    }

首先,beginArray和endArray就是加上中括号

  public JsonWriter beginArray() throws IOException {
    writeDeferredName();
    return open(EMPTY_ARRAY, "[");
  }

  public JsonWriter endArray() throws IOException {
    return close(EMPTY_ARRAY, NONEMPTY_ARRAY, "]");
  }

然后这里的elementTypeAdapter类型是TypeAdapterRuntimeTypeWrapper,看看他的write方法

  //获取到运行时的真正状态
  private Type getRuntimeTypeIfMoreSpecific(Type type, Object value) {
    if (value != null
        && (type == Object.class || type instanceof TypeVariable<?> || type instanceof Class<?>)) {
      type = value.getClass();
    }
    return type;
  }

  public void write(JsonWriter out, T value) throws IOException {
    TypeAdapter chosen = delegate;
    Type runtimeType = getRuntimeTypeIfMoreSpecific(type, value);
    if (runtimeType != type) {
      TypeAdapter runtimeTypeAdapter = context.getAdapter(TypeToken.get(runtimeType));
      if (!(runtimeTypeAdapter instanceof ReflectiveTypeAdapterFactory.Adapter)) {
        // The user registered a type adapter for the runtime type, so we will use that
        chosen = runtimeTypeAdapter;
      } else if (!(delegate instanceof ReflectiveTypeAdapterFactory.Adapter)) {
        // The user registered a type adapter for Base class, so we prefer it over the
        // reflective type adapter for the runtime type
        chosen = delegate;
      } else {
        // Use the type adapter for runtime type
        chosen = runtimeTypeAdapter;
      }
    }
    chosen.write(out, value);
  }

这里面传进来的type是E,也就是ArrayList里传递的泛型类型,真正的类型根据对象value获取,是User
接下来就是写一个个user,可以看上一节的分析,不过user之间的‘,’是在哪里添加的呢?

同样的,我们再来分析一下fromJson的实现,上面分析知道ArrayList对应的factory是CollectionTypeAdapterFactory,所以看他的read方法

    public Collection<E> read(JsonReader in) throws IOException {
      if (in.peek() == JsonToken.NULL) {
        in.nextNull();
        return null;
      }

      Collection<E> collection = constructor.construct(); //这里会创建一个集合
      in.beginArray();
      while (in.hasNext()) {
        E instance = elementTypeAdapter.read(in);
        collection.add(instance);
      }
      in.endArray();
      return collection;
    }

首先beginArray会判断json字符串是否以’[‘开头,如果不是,会抛出一个比较经典的错误提示

  public void beginArray() throws IOException {
    int p = peeked;
    if (p == PEEKED_NONE) {
      p = doPeek();
    }
    if (p == PEEKED_BEGIN_ARRAY) {
      push(JsonScope.EMPTY_ARRAY);
      pathIndices[stackSize - 1] = 0;
      peeked = PEEKED_NONE;
    } else {
      throw new IllegalStateException("Expected BEGIN_ARRAY but was " + peek()
          + " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath());
    }
  }

接下来,会依次调用elementTypeAdapter.read(in)读取每个对象,这里同样的会获取到真正的类型User,所以会调用ReflectiveTypeAdapterFactory内部Adapter的read方法,所以又会走上一节描述的地方。
我们知道,在运行期间,泛型信息是不会保存的,那么gson是如何避免泛型擦除的呢?
我们首先创建一个包含泛型的类

public class Foo<T> {

    private T data;

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

然后我们尝试解析

        Foo<User> foo = new Foo<User>();
        User user = new User("fcl", 24);
        foo.setData(user);
        Logger.error(TAG, foo.getClass().toString());

很遗憾,这里获取到的结果是 class com.example.fcl.gsondemo.Foo,也就是不包含泛型信息的,但是,如果我们这样写

        Foo<User> foo = new Foo<User>(){};
        User user = new User("fcl", 24);
        foo.setData(user);
        Type superclass = foo.getClass().getGenericSuperclass();
        Type type = ((ParameterizedType)superclass).getActualTypeArguments()[0];
        Logger.error(TAG, foo.getClass().toString() + "\n"
                         +superclass.toString() + "\n"
                         +type.toString());

这里打印出来的结果是

class com.example.fcl.gsondemo.MainActivity$1
com.example.fcl.gsondemo.Foo<com.example.fcl.gsondemo.User>
class com.example.fcl.gsondemo.User

首先这样写 new Foo(){} 是实现Foo的子类,这里是MainActivity的内部类,然后通过getGenericSuperclass获取父类,而且
此时可以看出,泛型的信息是保存着的。这是因为虚拟机在生成字节码文件时,是会保存泛型信息的,保存在signature字段里。随后
的getActualTypeArguments方法,则是获取Foo里的所有参数类型列表。
很显然,gson运用的就是这样一个原理,这也就解释了为什么我们调用的时候会这样写

List<User> users1 = gson.fromJson(s, new TypeToken<List<User>>(){}.getType());

那么我们再跟进去看一次

  protected TypeToken() {
    this.type = getSuperclassTypeParameter(getClass());
    this.rawType = (Class<? super T>) $Gson$Types.getRawType(type);
    this.hashCode = type.hashCode();
  }

  static Type getSuperclassTypeParameter(Class<?> subclass) {
    Type superclass = subclass.getGenericSuperclass();
    if (superclass instanceof Class) {
      throw new RuntimeException("Missing type parameter.");
    }
    ParameterizedType parameterized = (ParameterizedType) superclass;
    return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
  }

发现获取到type的方式确实和上述一样的,至此,关于gson避免泛型擦除的分析,也就告一段落了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值