关于android:Android-序列化框架-Gson-原理分析可以优化吗

39次阅读

共计 15962 个字符,预计需要花费 40 分钟才能阅读完成。

本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 发问。

前言

大家好,我是小彭。

Gson 是 Google 推出的 Java Json 解析库,具备接入成本低、应用便捷、性能扩展性良好等长处,想必大家都很相熟了。在这篇文章里,咱们将探讨 Gson 的根本用法和以及次要流程的源码剖析。


小彭的 Android 交换群 02 群曾经建设啦,扫描文末二维码进入~


学习路线图:


1. Gson 的根本应用

Gradle 依赖

dependencies {implementation 'com.google.code.gson:gson:2.10'}

1.1 GsonBuilder 配置项

Gson 类是整个库的外围 API,在进行任何序列化或反序列化之前,咱们都须要取得一个 Gson 对象。能够间接 new 创立默认配置的 Gson 对象,也能够应用 GsonBuilder 结构者配置 Gson 对象。

事实上,一个 Gson 对象代表一个 Gson 工作环境,不同 Gson 对象之间的配置和缓存都不会复用。 因而,在我的项目中有必要在 common 层提供一个全局的 Gson 对象,既有利于对立序列化配置,也是 Gson 性能优化的基本保障。

GsonBuilder 应用示例

Gson gson = new GsonBuilder()
    // 设置自定义解析(不反对协变).registerTypeAdapter(Id.class, new IdTypeAdapter())
    // 设置自定义解析(反对协变)registerTypeHierarchyAdapter(List.class, new MyListTypeAdapter())
    // 设置自定义解析(以工厂形式).registerTypeAdapterFactory(new IdTypeAdapterFactory())
    // 设置日期格局
    .setDateFormat("yyyy-MM-dd HH:mm:ss:SSS")
    // 设置主动切换命名格调规定(默认不切换命名格调).setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
    // 设置过滤指定字段标识符(默认只过滤 transient 和 static 字段).excludeFieldsWithModifiers(Modifier.TRANSIENT | Modifier.STATIC)
    // 设置类或字段过滤规定
    .setExclusionStrategies(new MyExclusionStrategy1())
    // 设置过滤规定(只实用于序列化).addSerializationExclusionStrategy(new MyExclusionStrategy2())
    // 设置过滤规定(只实用于反序列化).addDeserializationExclusionStrategy(new MyExclusionStrategy3())
    // 设置序列化版本号
    .setVersion(1.0)
    // 启用非根底类型 Map Key
    .enableComplexMapKeySerialization()
    // 启用不过滤空值(默认会过滤空值).serializeNulls()
    // 启用 Json 格式化
    .setPrettyPrinting()
    .create();

1.2 注解配置

Gson 没有编译时解决,所以注解均是运行时注解。

  • @SerializedName 字段别名: 反对设置多个别名,value 变量在序列化和反序列化时都无效,而 alternate 变量只是在反序列化时做兼容而已;
  • @Expose 字段裸露:

    • 默认状况下,一个类中所有字段都会裸露,但应用 @Expose 注解后,只有申明注解的字段才会裸露;
    • 注解的 serialize 变量或 deserialize 变量能够申明字段只参加序列化或反序列化,默认都参加。
  • @JsonAdapter 注解: 申明在具体类或字段上,用于更细粒度地设置 TypeAdapter,优先级比 registerTypeAdapter 高;
  • @Since 注解: 申明在具体类或字段上,申明字段的起始序列化版本;
  • @Until 注解: 申明在具体类或字段上,申明字段的终止序列化版本。当字段的序列化版本满足 since ≥ GsonBuilder#setVersion 且 GsonBuilder#setVersion ≤ until 时,才会参加序列化;

1.3 JsonSerializer 和 JsonDeserializer 自定义解析

JsonSerializerJsonDeserializer 是 Gson 1.x 版本提供的自定义解析 API,是基于树型构造的解析 API。在解析数据时,它们会将 Json 数据一次性解析为 JsonElement 树型构造。JsonElement 代表 Json 树上的一个节点,有 4 种具体类型:

JsonElement 形容
JsonObject {} 对象
JsonArray [] 数组
JsonPrimitive 根本类型
JsonNull null 值

1.4 TypeAdapter 自定义解析

TypeAdapter 是 Gson 2.0 新增的自定义解析 API,是基于流式构造的 API。事实上,JsonSerializer 和 JsonDeserializer 最终也会被结构为 TreeTypeAdapter

相较之下,JsonSerializer & JsonDeserializer 绝对不便,但更费内存。而 TypeAdapter 更节俭内存,但不不便。不过,如果须要用到残缺数据结构(例如依据 type 字段依照不同类型解析 data),也能够手动解析为树型构造。因而 TypeAdapter 这个 API 的优先级更高。

TypeAdapter JsonSerializer、JsonDeserializer
引入版本 2.0 1.x
Stream API 反对 不反对
Tree API 反对,能够手动转换 反对
内存占用 比 TypeAdapter 大
效率 比 TypeAdapter 低
作用范畴 序列化 + 反序列化 序列化 / 反序列化

1.5 registerTypeAdapter 和 registerTypeHierarchyAdapter 的区别

  • registerTypeAdapter 是不变型的: 只会对注册的类型失效。例如注册 <List.class,TypeAdapter>,则只会影响 List 类型的字段,但不会影响 ArrayList 类型的字段;
  • registerTypeHierarchyAdapter 是协变型的: 会对注册的类型及其子类失效。例如注册 <List.class,TypeAdapter>,则只会影响 ListArrayList 类型的字段;
registerTypeAdapter registerTypeHierarchyAdapter
反对泛型
反对继承

2. Gson 源码剖析

这一节,咱们来剖析 Gson 外围流程的工作原理和源码。

2.1 说一下 Gson 解析的工作过程

“TypeAdapter” 是 Gson 解析的重要角色,Gson 每次解析一种对象类型,首先须要创立一个 TypeAdapter 对象,之后所有的解析工作都会交给其中的 TypeAdapter#write 和 TypeAdapter#read 办法;

Java Bean 类型的 TypeAdapter 对象是交给 “ReflectiveTypeAdapterFactory” 创立的。每创立一种类型的 TypeAdapter,都须要递归地应用 “反射” 遍历所有字段,并解析字段上的注解,生成一个 <serializeName - BoundFiled> 的映射表。

  • 在序列化时,首先应用反射获取字段值,再应用字段的 BoundFiled 序列化;
  • 在反序列化时,首先创建对象实例(下文会探讨如何创立),再应用顺次应用字段的 BoundField 反序列为字段类型的值,再通过反射为字段赋值。

因为字段值的写入和读取是通过 Field 元数据反射操作的,所以 private 字段也能够操作。

在结构 Gson 对象时,曾经初始化了一系列 TypeAdapter 创立工厂,开发者能够注册自定义的 TypeAdapter:

Gson.java

Gson(final Excluder excluder, ...) {List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>();

    // built-in type adapters that cannot be overridden
    factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);
    factories.add(ObjectTypeAdapter.FACTORY);

    // 过滤规定
    factories.add(excluder);

    // 自定义 TypeAdapter
    factories.addAll(factoriesToBeAdded);

    // 1. 根底类型
    factories.add(TypeAdapters.STRING_FACTORY);
    factories.add(TypeAdapters.INTEGER_FACTORY);
    ...
    // 2. 复合类型
    // 2.1 列表类型
    factories.add(new CollectionTypeAdapterFactory(constructorConstructor));
    // 2.2 汇合类型
    factories.add(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization));
    this.jsonAdapterFactory = new JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor);
    factories.add(jsonAdapterFactory);
    // 2.3 枚举类型
    factories.add(TypeAdapters.ENUM_FACTORY);
    // 2.4 Java Bean 类型
    factories.add(new ReflectiveTypeAdapterFactory(constructorConstructor, fieldNamingStrategy, excluder, jsonAdapterFactory));
}

通过 Gson#getAdapter 查找匹配 TypeAdapter 的办法:

Gson.java

// TypeAdapter 缓存映射表 <Type - TypeAdapter>
private final Map<TypeToken<?>, TypeAdapter<?>> typeTokenCache = new ConcurrentHashMap<TypeToken<?>, TypeAdapter<?>>();

public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
    // 先从映射表缓存中查找
    TypeAdapter<?> cached = typeTokenCache.get(type);
    if (cached != null) {return (TypeAdapter<T>) cached;
    }
    // 再通过 TypeAdapter 创立工厂创立,并退出映射表缓存中
    for (TypeAdapterFactory factory : factories) {
        // 从前到后线性扫描创立工厂,找到适合的 TypeAdapter
        TypeAdapter<T> candidate = factory.create(this, type);
        if (candidate != null) {
            // 退出缓存中
            typeTokenCache.put(type, candidate);
            return candidate;
        }
    }
}

应用 ReflectiveTypeAdapterFactory 工厂为每种类型创立 TypeAdapter 对象:

ReflectiveTypeAdapterFactory.java

// 1. 创立 TypeAdapter 对象
@Override
public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {Class<? super T> raw = type.getRawType();
    // 查看是否为 Object 类型
    if (!Object.class.isAssignableFrom(raw)) {return null; // it's a primitive!}
    // 1.1 获取对象结构器(下文剖析)ObjectConstructor<T> constructor = constructorConstructor.get(type);
    // 1.2 getBoundFields:解析每个字段的适配器
    // 1.3 FieldReflectionAdapter:TypeAdapter 对象(Adapter 类型)return new FieldReflectionAdapter<T>(constructor, getBoundFields(gson, type, raw));
}

public static abstract class Adapter<T, A> extends TypeAdapter<T> {
    final Map<String, BoundField> boundFields;
        
    // 2. 反序列化过程
    @Override 
    public T read(JsonReader in) {
        // 2.1 创建对象
        T instance = constructor.construct();
        // 2.2 生产 {in.beginObject();
        // 2.3 递归反序列化每个字段
        while (in.hasNext()) {String name = in.nextName();
              BoundField field = boundFields.get(name);
              if (field == null || !field.deserialized) {in.skipValue();
              } else {
                    // 读取流并设置到 instance 对象中
                    readIntoField(in, instance);
              }
        }
        // 2.4 生产 }
        in.endObject();
        return instance;
    }

    // 3. 序列化过程
    @Override
    public void write(JsonWriter out, T value) {
        // 3.1 写入 {out.beginObject();
        // 3.2 递归序列化每个字段
        for (BoundField boundField : boundFields.values()) {
            // 将对象的每个字段写入流中
            boundField.write(out, value);
        }
        // 3.3 写入 }
        out.endObject();}
}

// -> 1.2 getBoundFields:解析每个字段的适配器
private Map<String, BoundField> getBoundFields(Gson context, TypeToken<?> type, Class<?> raw, boolean blockInaccessible, boolean isRecord) {
    // 1.2.1 映射表
    Map<String, BoundField> result = new LinkedHashMap<>();
    if (raw.isInterface()) {return result;}
    ...
    // 1.2.2 遍历所有 Field
    Field[] fields = raw.getDeclaredFields();
    for (Field field : fields) {
        // 1.2.2.1 字段过滤
        boolean serialize = includeField(field, true);
        boolean deserialize = includeField(field, false);
        if (!serialize && !deserialize) {continue;}
        // 1.2.2.2 获取字段的所有别名,第 0 位是主名称
        List<String> fieldNames = getFieldNames(field);
        // 1.2.2.3 为所有字段别名创立 BoundField 对象
        for (int i = 0, size = fieldNames.size(); i < size; ++i) {String name = fieldNames.get(i);
            // serialize = false 这一行阐明:序列化时是采纳字段的主名称
            if (i != 0) serialize = false;
            BoundField boundField = createBoundField(context, field, accessor, name, TypeToken.get(fieldType), serialize, deserialize, blockInaccessible);
            BoundField replaced = result.put(name, boundField);
            if (previous == null) previous = replaced;
        }
        // 1.2.2.4 存在两个的字段应用雷同 serializeName 的抵触
        if (previous != null) {throw new IllegalArgumentException(declaredType + "declares multiple JSON fields named" + previous.name);
        }
    }
    // 1.2.3 返回映射表
    return result;
}

// -> 1.2.2.3 为所有字段别名创立 BoundField 对象
private ReflectiveTypeAdapterFactory.BoundField createBoundField(
      final Gson context, final Field field, final String name,
      final TypeToken<?> fieldType, boolean serialize, boolean deserialize) {
    // 根本类型
    final boolean isPrimitive = Primitives.isPrimitive(fieldType.getRawType());
    // @JsonAdapter 注解
    JsonAdapter annotation = field.getAnnotation(JsonAdapter.class);
    TypeAdapter<?> mapped = null;
    if (annotation != null) {mapped = jsonAdapterFactory.getTypeAdapter(constructorConstructor, context, fieldType, annotation);
    }
    final boolean jsonAdapterPresent = mapped != null;
    if (mapped == null) mapped = context.getAdapter(fieldType);
    final TypeAdapter<?> typeAdapter = mapped;
    return new ReflectiveTypeAdapterFactory.BoundField(name, serialize, deserialize) {

        @Override 
        void write(JsonWriter writer, Object value) {if (!serialized) return;
            // 通过反射读取字段值
            Object fieldValue = field.get(value);
            TypeAdapter t = jsonAdapterPresent ? typeAdapter : new TypeAdapterRuntimeTypeWrapper(context, typeAdapter, fieldType.getType());
            // 写出到流
            t.write(writer, fieldValue);
        }
        
        @Override
        void readIntoField(JsonReader reader, Object target) {
            // 从流读取
            Object fieldValue = typeAdapter.read(reader);
            // 通过反射写入字段值
            field.set(target, fieldValue);
        }
    };
}

2.2 List & Set & Map 等容器类型是如何解析的?

  • 1、在预置的容器 TypAdapter 中,会先通过容器类型的 RawType 获取容器结构器,再依据泛型实参 elementType 获取元素类型的 TypeAdapter;
  • 2、在序列化时,先写入 [左中括号,再用元素类型的 TypeAdapter 顺次序列化元素对象,再写入] 右中括号;
  • 3、在反序列化时,先创立汇合对象,再用元素类型的 TypeAdapter 顺次反序列化元素对象;
  • 4、Map 类型须要保护 Key 和 Value 两个 TypeAdapter。

CollectionTypeAdapterFactory.java

// 1. 创立 TypeAdapter
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {Type type = typeToken.getType();
    // 查看是否为列表类型
    Class<? super T> rawType = typeToken.getRawType();
    if (!Collection.class.isAssignableFrom(rawType)) {return null;}
    // 1.1 解析元素类型
    Type elementType = $Gson$Types.getCollectionElementType(type, rawType);
    // 1.2 查找元素类型映射的 TypeAdapter
TypeAdapter<?> elementTypeAdapter = gson.getAdapter(TypeToken.get(elementType));
    // 1.3 解析容器对象的结构器
ObjectConstructor<T> constructor = constructorConstructor.get(typeToken);
    // 1.4 包装新的 TypeAdapter
    TypeAdapter<T> result = new Adapter(gson, elementType, elementTypeAdapter, constructor);
}

private static final class Adapter<E> extends TypeAdapter<Collection<E>> {
    // 2. 反序列化过程
    @Override 
    public Collection<E> read(JsonReader in) {
        // 2.1 创立容器对象
        Collection<E> collection = constructor.construct();
        // 2.2 生产 [in.beginArray();
        // 2.3 应用 1.2 步骤的 TypeAdapter 反序列化每个元素
        while (in.hasNext()) {E instance = elementTypeAdapter.read(in);
            collection.add(instance);
        }
        // 2.4 生产 ]
        in.endArray();
        return collection;
    }

    // 3. 序列化过程
    @Override 
    public void write(JsonWriter out, Collection<E> collection) {
        // 3.1 写入 [out.beginArray();
        // 3.2 应用 1.2 步骤的 TypeAdapter 序列化每个元素
        for (E element : collection) {elementTypeAdapter.write(out, element);
        }
        // 3.3 写入 ]
        out.endArray();}
}

2.3 枚举类型是如何解析的?

  • 1、在预置的 EnumTypeAdapter 适配器中,会先获取枚举类型的整个枚举列表,并生成 2 个映射表。

    • <name – 枚举 > 映射表
    • < 枚举 – name> 映射表
  • 2、在序列化时,会写入枚举的 name。在反序列化时,会依据 name 查问枚举对象。

TypeAdapters.java

private static final class EnumTypeAdapter<T extends Enum<T>> extends TypeAdapter<T> {
    // <name - 枚举 > 映射表
    private final Map<String, T> nameToConstant = new HashMap<String, T>();
    // < 枚举 - name> 映射表
    private final Map<T, String> constantToName = new HashMap<T, String>();

    public EnumTypeAdapter(Class<T> classOfT) {for (T constant : classOfT.getEnumConstants()) {String name = constant.name()
            nameToConstant.put(name, constant);
            constantToName.put(constant, name);
        }
    }

    @Override 
    public T read(JsonReader in) {return nameToConstant.get(in.nextString());
    }

    @Override 
    public void write(JsonWriter out, T value) {out.value(constantToName.get(value));
    }
}

2.4 同类型嵌套会不会有限递归?

ReflectiveTypeAdapterFactory 在创建对象的 TypeAdapter 适配器时,须要递归的创立每个字段的 TypeAdapter。如果字段的类型正好与类的类型雷同,那么又会触发创立一个雷同的 TypeAdapter,造成有限递归。例如:

有限递归的例子

public class Article {public Article linkedArticle;}

剖析发现,有限递归只产生在第一次创立某个 Java Bean 类型的 TypeAdapter 时,而下一次会从缓存获取,不会产生有限递归。因而,Gson 的做法是:

  • 1、在每次新创建 TypeAdapter 前,先在长期映射表中创立一个 FutureTypeAdapter 代理对象。在创立实在的 TypeAdapter 后,将其注入到代理对象中。这样在递归获取字段的 TypeAdapter 时,就会拿到代理对象,而不是从新创立 TypeAdapter,因而解决递归问题;
  • 2、另外,思考到多线程环境下,长期映射表的新增和移除会有并发问题,因而 Gson 的策略是应用 ThreadLocal 隔离各个线程的长期映射表。

Gson.java

// 线程隔离的映射表
private final ThreadLocal<Map<TypeToken<?>, FutureTypeAdapter<?>>> calls = new ThreadLocal<Map<TypeToken<?>, FutureTypeAdapter<?>>>();
// 线程共享的映射表(基于 ConrurrentHashMap)private final Map<TypeToken<?>, TypeAdapter<?>> typeTokenCache = new ConcurrentHashMap<TypeToken<?>, TypeAdapter<?>>();

public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
    // 1. 尝试从缓存获取
    TypeAdapter<?> cached = typeTokenCache.get(type);
    if (cached != null) {return (TypeAdapter<T>) cached;
    }

    // 2. 初始化以后线程的长期映射表
    Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();
    boolean requiresThreadLocalCleanup = false;
    if (threadCalls == null) {threadCalls = new HashMap<TypeToken<?>, FutureTypeAdapter<?>>();
        calls.set(threadCalls);
        requiresThreadLocalCleanup = true;
    }

    // 3. 尝试从长期映射表获取(递归调用时,会从这里获取到代理 TypeAdapter,而不会走到上面的 factory.create
    FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);
    if (ongoingCall != null) {return ongoingCall;}

    try {
        // 4.1 创立代理 TypeAdapter
        FutureTypeAdapter<T> call = new FutureTypeAdapter<T>();
        threadCalls.put(type, call);

        for (TypeAdapterFactory factory : factories) {
            // 4.2 创立 TypeAdapter
            TypeAdapter<T> candidate = factory.create(this, type);
            // 4.3 将实在的 TypeAdapter 注入到代理 TypeAdapter 中
            if (candidate != null) {call.setDelegate(candidate);
                // 4.4 将 TypeAdapter 写入缓存
                typeTokenCache.put(type, candidate);
                return candidate;
            }
        }
    } finally {
        // 5. 革除长期映射表
        threadCalls.remove(type);
    
        if (requiresThreadLocalCleanup) {calls.remove();
        }
    }
}

2.5 Gson 是如何创建对象的?

  • 1、根底类型:Integer、Calendar 等根底类型由固定的 TypeAdapter,会通过 new 关键字创建对象;
  • 2、枚举:枚举的序列化和反序列化只是在枚举名 name 和枚举对象之间切换,不会创立新的枚举对象;
  • 3、List & Set & Map:容器类型会通过预置的对象创立工厂,调用 new 关键字创建对象;
  • 4、Java Bean:Java Bean 的创立分为多种可能:

    • 状况 1:自定义了对象创立工厂 InstanceCreator,则优先通过自定义工厂创立;
    • 状况 2:存在默认的无参构造函数,则通过反射构造函数创立;
    • 状况 3:应用 Unsafe API 兜底创建对象。

ConstructorConstructor.java

public <T> ObjectConstructor<T> get(TypeToken<T> typeToken) {final Type type = typeToken.getType();
    final Class<? super T> rawType = typeToken.getRawType();
        
    // InstanceCreator API
    final InstanceCreator<T> typeCreator = (InstanceCreator<T>) instanceCreators.get(type);
    if (typeCreator != null) {return new ObjectConstructor<T>() {
            @Override 
            public T construct() {return typeCreator.createInstance(type);
            }
        };
    }
    final InstanceCreator<T> rawTypeCreator = (InstanceCreator<T>) instanceCreators.get(rawType);
    if (rawTypeCreator != null) {return new ObjectConstructor<T>() {
            @Override 
            public T construct() {return rawTypeCreator.createInstance(type);
            }
        };
    }
    // 无参构造函数
    ObjectConstructor<T> defaultConstructor = newDefaultConstructor(rawType);
    if (defaultConstructor != null) {return defaultConstructor;}

    // 容器类型
    ObjectConstructor<T> defaultImplementation = newDefaultImplementationConstructor(type, rawType);
    if (defaultImplementation != null) {return defaultImplementation;}

    // Unsafe API
    return newUnsafeAllocator(type, rawType);
}

2.6 Gson 暗藏的坑

当 Class 未提供默认的无参构造函数时,Gson 会应用 Unsafe API 兜底来创建对象。Unsafe API 次要提供一些用于执行低级别、不平安操作的办法,也提供了一个非常规实例化对象的 allocateInstance 办法。

这个 API 不会调用构造函数 <init>,因而相干的结构初始化操作会失落;

  • 1、结构函数参数的默认值失落;
  • 2、字段的默认值失落;
  • 3、Kotlin 非空类型生效;
  • 4、初始化块未执行;
  • 5、by 属性代理(没有创立代理对象)

3. Gson 如何解析泛型类型?

因为 Java 有泛型擦除,无奈间接在 .class 语法上申明泛型信息,Gson 的办法是要求程序员创立匿名外部类,由 Gson 在运行时通过反射获取类申明上的泛型信息。

示例代码

// 非法:Response<User> obj = Gson().fromJson<Response<User>>(jsonStr, Response<User>.class)
// 非法;TypeToken token = object : TypeToken<Response<User>>() {}
Response<User> obj = Gson().fromJson<Response<User>>(jsonStr, token.type)

为什么反序列化泛型类要应用匿名外部类呢?

原理是 Class 文件中的 Signature 属性会放弃类签名信息,而 TypeToken 只是一个工具类,外部通过反射获取类签名中泛型信息并返回 Type 类型。

TypeToken.java

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

// 返回 Response<User>
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]);
}

public final Type getType() {return type;}

既然 TypeToken 只是一个获取 Type 类型的工具类,咱们也能够跳过它间接提供 Type,办法是定义 ParameterizedType 参数化类型的子类:

ParameterizedTypeAdapter.java

private static class ParameterizedTypeAdapter implements ParameterizedType {

    private final Class<?> rawType;
    private final Type[] types;

    private ParameterizedTypeAdapter(Class<?> rawType, Type... types) {
        this.rawType = rawType;
        this.types = types;
    }

    @Override
    public Type[] getActualTypeArguments() {return types;}

    @Override
    public Type getRawType() {return rawType;}

    @Override
    public Type getOwnerType() {return null;}
}

示例代码

Response<User> obj = new Gson().fromJson<Response<User>>(jsonStr, ParameterizedTypeAdapter(Response.class, User.class))

在 Kotlin 中,还能够应用 reified 实化类型参数简化:

Utils.kt

inline fun <reified T> toList(jsonStr: String): List<T> =
    Gson().fromJson(content, ParameterizedTypeAdapter(List::class.java, T::class.java))

inline fun <reified T> toObject(jsonStr: String): List<T> =
    Gson().fromJson(content, T::class.java))

示例代码

List<User> obj = toList<User>(jsonStr)

4. 总结

明天,咱们探讨了 Gson 的根本用法和以及次要流程的源码剖析。

在 Gson 的反序列化中,首次反序列化一个类型的对象时,Gson 须要应用大量反射调用解析一个 TypeAdapter 适配器对象。随着 Model 的复杂程度减少,首次解析的耗时会一直收缩。

这个问题在抖音的技术博客中提到一个解决方案,这个问题咱们在下篇文章探讨,请关注。


参考资料

  • Java Google Json (Gson) Introduction Introduction”) —— Mithil Shah 著
  • Gson — Getting Started with Java-JSON —— Norman Peitek 著
  • Javadoc · Gson —— Gson 官网文档
  • Gson 源码解析和它的设计模式 —— 拉丁吴 著
  • 还在被数据类的序列化折磨?是时候抛弃 Gson 了—— bennyhuo 著
  • 抖音 Android 性能优化系列:启动优化实际(反序列化优化)—— 字节跳动技术团队 著
  • JSON —— Wikipedia

小彭的 Android 交换群 02 群

正文完
 0