平时我们json解析常用到Gson,fastJson,Moshi等等,但是大家懂得他们为何可以反序列化出相应对象吗?如果想提示解析性能我们该如何优化?如果对应json的某个字段是数组类型,但是接口却返回了null,我们又该如何处理呢?
问题1:Gson比JsonArray+JsonObject的优点是什么?
Gson使用的是通过词法分析方式,配合json字符的入栈出栈动态载入内存,相比较JsonArray+JsonObject而言更省内存。
以“{”和“}”为例,在当“{”入栈后,只要一直没匹配到“}”,那么就一直往堆栈压入json字符,否则就将最近的“{}”以及其中的字段解析成对应的Object,并且这部分出栈,直至解析完毕。反序列化解析效果图如下:
问题2:为什么会说Gson反序列化操作是一个比较消耗性能的操作?
在Gson解析的过程中,所有的解析操作都是通过TypeAdapter来解析的,每一个属性以及每个对象都对应一个TypeAdapter。
但是问题来了,Gson只认识基本类型对应的TypeAdapter,但是对于"{.....}"这整块对象对应的TypeAdapter,Gson是不认识的,也没法认识,对象千千万,如果由Gson都来实现是不切合实际的。故而Gson在解析到这块后,发现不属于任何已知的基本类型对应的TypeAdapter,便只能通过反射构建相应的TypeAdapter对象,每一个对象对应一个适配器,每个相应适配器也只能通过反射方式创建以及填充出相应对象,这便是Gson反序列化消耗性能的原因所在。对应的执行反射操作的类为ReflectiveTypeAdapterFactory。
问题3:既然Gson反序列化比较消耗性能,但是某些庞大复杂json又想高效的去解析,我们又该如何操作呢?
Gson消耗性能的原因在于反射,所以优化的目标也就是免反射,所有的解析都是通过集成TypeAdapter的类来解析的,所以我们也可以自定义自己的TypeAdapter,在其中实现自己对象的序列化以及反序列化的过程即可。
使用示例如下:
问题4:自定义TypeAdapter的局限性
由于自定义的适配器是和当前类型是一一对应的,所以但凡涉及到其他类的适配器操作时,也是要用到同样方式书写相应的读写操作。那么有没有去掉这一过程的方式呢?想一想,通过动态注解如何?答案是肯定的,并且Square公司早已推出相应第三方库:Moshi,Square公司出品,必属精品,牛。答案已经说出来了,Moshi正是通过加入注解,编译期间动态帮我们生成对应的适配器,免去了书写的麻烦。
可以看出,由于实现方式的少许不同,注解生成的类继承的是JsonAdapter,而我们手写的是集成TypeAdapter。
需要注意的地方是,java bean必须是Kotlin的data class数据类,这是实现决定的,调用的地方无论java,kotlin都可。