今天看看数组相关的转换
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避免泛型擦除的分析,也就告一段落了。