一、 主流解析方式对比
解析方式 | 使用难度 | 原理 | 优点 | 缺点 | 适用场景 |
---|---|---|---|---|---|
Android原生 | 复杂 | 基于文档驱动 | 不依赖第三方库;处理速度快(不使用反射) | 使用复杂;内存消耗大;兼容性差 | 需要解析的JSON的格式固定且数量一般 |
Gson | 简单 | 基于事件驱动 | 使用简单;兼容性好 | 无 | 常规JSON数据量的项目 |
Fastjson | 简单 | 基于事件驱动 | 特大数据量的情况下处理速度快 | 兼容性一般;初始化速度慢 | JSON处理量特别大 |
二、详细说明
①Fastjson解析
技术分析
根据所需取的数据 建立1个对应于JSON
数据的JavaBean
类,即可通过简单操作解析出所需数据
主要缺点
- 数据类型兼容一般,例如对Date类型的支持
- 初始化速度较慢
主要优点
- 使用简单
适用场景
- JSON处理量特别大
使用示例
引入Fastjson implementation 'com.alibaba:fastjson:1.2.55'
// 读取JSON字符串(详见 三、数据准备-small.json)
String jsonStr = readJsonFile("small.json");
// 反序列化对象
DataBean data = JSON.parseObject(jsonStr,DataBean.class);
// 序列化对象
String newJsonStr = JSON.toJSONString(data);
// 读取JSON字符串(详见 三、数据准备-big.json)
jsonStr = readJsonFile("big.json");
BaseBean<List<DataBean>> newBaseBean = JSON.parseObject(jsonStr,new TypeReference<BaseBean<List<DataBean>>>(){});
复杂数据处理(泛型)
处理带有泛型的复杂数据格式时fromJson方法的第二参数应传入new TypeReference<返回的实体类型>(){}
如上代码如果fromJson方法的第二参数传入BaseBean<List<DataBean>>.class
,因JAVA泛型擦除机制,泛型<List<DataBean>>
是无效的,会抛出com.google.gson.JsonSyntaxException: java.lang.IllegalStateException
等异常
② Gson解析
技术分析
根据所需取的数据 建立1个对应于JSON
数据的JavaBean
类,即可通过简单操作解析出所需数据
主要缺点
主要优点
- 使用简单
- 数据类型兼容性强.
- 常规数据量下速度良好
适用场景
- 常规JSON数据量的项目
使用示例
引入GOSN implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.6'
// 读取简单JSON字符串(详见 三、数据准备-small.json)
String jsonStr = readJsonFile("small.json");
// 创建Gson对象
Gson gson = new Gson();
// 反序列化对象
DataBean data = gson.fromJson(jsonStr,DataBean.class);
// 序列化对象
String newJsonStr = gson.toJson(data);
// 读取复杂JSON字符串(详见 三、数据准备-big.json)
jsonStr = readJsonFile("big.json");
BaseBean<List<DataBean>> newBaseBean = new Gson().fromJson(jsonStr,new TypeToken<BaseBean<List<DataBean>>>(){}.getType());
复杂数据处理(泛型)
处理带有泛型的复杂数据格式时fromJson方法的第二参数应传入new TypeToken<返回的实体类型>(){}.getType()
如上代码如果fromJson方法的第二参数传入BaseBean<List<DataBean>>.class
,因JAVA泛型擦除机制,泛型<List<DataBean>>
是无效的,会抛出com.google.gson.JsonSyntaxException: java.lang.IllegalStateException
等异常
③ Android原生解析
技术分析
解析流程:把全部文件读入到内存中 ->> 遍历所有数据 ->> 根据需要检索想要的数据
主要缺点
- Android原生解析没有提供直接将对象与JSON字符串互相转换的方法,需要根据实体类各字段根据数据类型逐一设置,或利用反射实现.使用复杂,兼容性差.
- 基于文档驱动, 不能按需读取, 解析特别大的json数据时内存消耗较大.
主要优点
- 不需要引入第三方库,可以缩减包的体积,降低第三方库版本的维护成本.
适用场景
- 项目全局需要解析的JSON格式固定且种类较少,可以自己封装相关处理方法.减少对第三方库的依赖.
- 需要解析的数据量较少,性能要求不高时可以考虑使用
使用示例
反序列化
// 读取JSON字符串(详见 三、数据准备-small.json)
String jsonStr = readJsonFile("small.json");
// 反序列化JSON
JSONObject jsonObject = new JSONObject(jsonStr);
// 声明反序列化结果对象
DataBean data = new DataBean();
// 获取反序列化结果的属性值并赋值
data.setBooleanData(jsonObject.getBoolean("booleanData"));
data.setByteData((byte) jsonObject.getInt("byteData"));
data.setShortData((short) jsonObject.getInt("shortData"));
data.setIntegerData(jsonObject.getInt("integerData"));
data.setLongData(jsonObject.getLong("longData"));
data.setFloatData((float) jsonObject.getDouble("floatData"));
data.setDoubleData(jsonObject.getDouble("doubleData"));
data.setStringData(jsonObject.getString("stringData"));
data.setDateData(sdf.parse(jsonObject.getString("dateData")));
JSONArray array = jsonObject.getJSONArray("arrayData");
String[] arrayData = new String[array.length()];
for (int i = 0; i < array.length(); i++) {
arrayData[i] = array.get(i).toString();
}
data.setArrayData(arrayData);
List<String> listData = new ArrayList<>();
for (int i = 0; i < jsonObject.getJSONArray("listData").length(); i++) {
listData.add(jsonObject.getJSONArray("listData").getString(i));
}
data.setListData(listData);
Map<String,String> mapData = new HashMap<>();
JSONObject map = jsonObject.getJSONObject("mapData");
map.names();
for (int i = 0; i < map.names().length(); i++) {
String key = map.names().get(i).toString();
mapData.put(key,map.get(key).toString());
}
data.setMapData(mapData);
// 输出反序列化结果对象
...详见输出结果-反序列化得到的对象
输出结果
-
反序列化得到的对象
data.BooleanData: true data.ByteData(数字): 127 data.ShortData: 32767 data.IntegerData: 2147483647 data.LongData: 9223372036854775807 data.FloatData: 3.4028235E38 data.DoubleData: 1.7976931348623157E308 data.StringData: 字符串 data.DateData: 2020-10-26 data.ArrayDataData: ["Array元素1", "Array元素2", "Array元素3"] data.ListData: ["List元素1", "List元素2", "List元素3"] data.MapData: {"Map Key3": "Map Value3","Map Key1": "Map Value1","Map Key2": "Map Value2"}
序列化
JSONStringer jsonStringer = new JSONStringer();
jsonStringer.key("status").value(1);
jsonStringer.key("message").value("提示信息");
String jsonStr = jsonStringer.toString();
// 输出序列化结果JSON字符串
输出结果
-
序列化结果JSON字符串
{"status":1,"message":"提示信息"}
代码分析
android原生解析JSON工具 包名为:org.json
。这个包下主要有四个类:
-
JSONObject
该类表示了一个可更改且无序的键值对集合,简单来说直接认为这个类表示了一个 JSON 的信息。
在 JSON 字符串中,其表示了一个包裹在花括号的字符串,键和值之间使用冒号隔开,键值和键值之间使用逗号隔开的。
JSONArray类中,其键名是唯一且不为
null
的字符串。而值则可以为JSONObject
、JSONArray
、Strings
、Booleans
、Integers
、Longs
、Double
或者JSONObject.NULL
。特别注意,这里的NULL
可不是null
,而是JSONObject
的一个内部类。-
刚说到此类中的
NULL
,它与 JAVA 中的null
是不一样的,它仅仅是JSONObject
中用于标识null
的对象。举个例子:-
put(name, null)
这个方法调用将会移除该对象中对应的键值; -
put(name, JSONObject.NULL)
将会往对象中添加一个键值,而其值为JSONObject.NULL
;
-
-
对于这个类,在使用时要要注意的就是在调用时,其会按照调用的方法进行类型转换。下面就介绍一下三类函数:
-
getXXX()
获取一个值,此方法如果发生失败,例如没有找到对应的键值或类型转换失败,就会抛出一个JSONException
异常; -
optXXX()
此类方法也是用于获取一个值,但是如果发生失败,其不会抛出异常,而是返回一个默认值; -
put()
此类方法就是向对象中插入一个键值对。特别注意其插入NULL
和null
是不同的;
-
-
JSONArray
- 该类表示了 JSON 中的值的数组,可以简单的理解其为一个普通数组,也有
getXXX()
和optXXX()
方法,但是基本都需要传入索引值。这个类代表了JSON 中的一个包裹在方括号的字符串,值和值之间使用逗号隔开的信息。
- 该类表示了 JSON 中的值的数组,可以简单的理解其为一个普通数组,也有
-
JSONStringer
- 此类可以用于快速构建 JSON 字符串,它实现了
JSONObject
中的两个toString()
方法,对于大多数程序员来说,应该直接调用JSONObject
的toString()
方法而忽略这个类的:
- 此类可以用于快速构建 JSON 字符串,它实现了
-
JSONTokener
- 这个类是四个类中最不常用的一个类,它能够将一个 JSON 字符串(RFC 4627)解析到相关的对象,对于大多数客户端仅仅需要使用它的构造函数和
nextValue()
函数:
- 这个类是四个类中最不常用的一个类,它能够将一个 JSON 字符串(RFC 4627)解析到相关的对象,对于大多数客户端仅仅需要使用它的构造函数和
三、数据准备
-
简单JSON - DataBean.json
{ "arrayData": ["Array元素1", "Array元素2", "Array元素3"], "booleanData": true, "byteData": 127, "dateData": "2020-10-26", "doubleData": 1.7976931348623157E308, "floatData": 3.4028235E38, "integerData": 2147483647, "listData": ["List元素1", "List元素2", "List元素3"], "longData": 9223372036854775807, "mapData": { "Map Key3": "Map Value3", "Map Key1": "Map Value1", "Map Key2": "Map Value2" }, "shortData": 32767, "stringData": "字符串" }
-
简单JSON对应的实体类 DataBean
public class DataBean { private Boolean booleanData; private Byte byteData; private Short shortData; private Integer integerData; private Long longData; private Float floatData; private Double doubleData; private String stringData; private Date dateData; private String[] arrayData; private List<String> listData; private Map<String,String> mapData; // 省略GET SET方法.... }
-
复杂JSON - big.json
{ "status": "success", "message": "提示信息", "data": [{ "arrayData": ["Array元素1", "Array元素2", "Array元素3"], "booleanData": true, "byteData": 127, "dateData": "2020-10-26", "doubleData": 1.7976931348623157E308, "floatData": 3.4028235E38, "integerData": 2147483647, "listData": ["List元素1", "List元素2", "List元素3"], "longData": 9223372036854775807, "mapData": { "Map Key3": "Map Value3", "Map Key1": "Map Value1", "Map Key2": "Map Value2" }, "shortData": 32767, "stringData": "字符串" }, { "arrayData": ["Array元素1", "Array元素2", "Array元素3"], "booleanData": true, "byteData": 127, "dateData": "2020-10-26", "doubleData": 1.7976931348623157E308, "floatData": 3.4028235E38, "integerData": 2147483647, "listData": ["List元素1", "List元素2", "List元素3"], "longData": 9223372036854775807, "mapData": { "Map Key3": "Map Value3", "Map Key1": "Map Value1", "Map Key2": "Map Value2" }, "shortData": 32767, "stringData": "字符串" }, { "arrayData": ["Array元素1", "Array元素2", "Array元素3"], "booleanData": true, "byteData": 127, "dateData": "2020-10-26", "doubleData": 1.7976931348623157E308, "floatData": 3.4028235E38, "integerData": 2147483647, "listData": ["List元素1", "List元素2", "List元素3"], "longData": 9223372036854775807, "mapData": { "Map Key3": "Map Value3", "Map Key1": "Map Value1", "Map Key2": "Map Value2" }, "shortData": 32767, "stringData": "字符串" }, { "arrayData": ["Array元素1", "Array元素2", "Array元素3"], "booleanData": true, "byteData": 127, "dateData": "2020-10-26", "doubleData": 1.7976931348623157E308, "floatData": 3.4028235E38, "integerData": 2147483647, "listData": ["List元素1", "List元素2", "List元素3"], "longData": 9223372036854775807, "mapData": { "Map Key3": "Map Value3", "Map Key1": "Map Value1", "Map Key2": "Map Value2" }, "shortData": 32767, "stringData": "字符串" }, { "arrayData": ["Array元素1", "Array元素2", "Array元素3"], "booleanData": true, "byteData": 127, "dateData": "2020-10-26", "doubleData": 1.7976931348623157E308, "floatData": 3.4028235E38, "integerData": 2147483647, "listData": ["List元素1", "List元素2", "List元素3"], "longData": 9223372036854775807, "mapData": { "Map Key3": "Map Value3", "Map Key1": "Map Value1", "Map Key2": "Map Value2" }, "shortData": 32767, "stringData": "字符串" }] }
-
复杂JSON对应的实体类 BaseBean
public class BaseBean<T> { private Status status; private String message; // 文中数据 泛型T => List<DataBean> private T data; public enum Status { success, fail } // 省略GET SET方法.... }
四、速度测试
解析数据对比
统计单位: 序列化和反序列化各执行1次的平均时间(单位 ms)
解析方式 | 简单数据(含初始化) | 复杂数据 | 较长数据<br />(100个简单数据的集合) | 超长数据<br />(10000个简单数据的集合) |
---|---|---|---|---|
Android原生 | 7 | 11 | 150 | 2652 |
Gson | 50 | 10 | 85 | 1150 |
Fastjson | 220 | 20 | 110 | 1985 |
统计单位: 序列化和反序列化各执行10000次的平均时间(单位 ms)
解析方式 | 简单数据(含初始化) | 复杂数据 | 较长数据<br />(100个简单数据的集合) | 超长数据<br />(10000个简单数据的集合) |
---|---|---|---|---|
Android原生 | 2533 | 7963 | 159302 | |
Gson | 11188 | 12596 | 99247 | |
Fastjson | 2230 | 5777 | 98905 |
数据说明
- Fastjson初始化很慢,项目中JSON处理不是特别频繁的情况下Fastjson各方面都不如Gson和Android原生处理
- Android原生处理初始化速度最快,虽然在数据较长时表现不如Fastjson,但优化测试代码后速度应还有提升空间
- Gson在初始化速度上不如Android原生处理但优于Fastjson,频繁处理速度远低于Fastjson和Android原生处理
测试代码
// 读取简单JSON
String smallStr = readJsonFile("small.json");
// 读取复杂JSON
String bigStr = readJsonFile("big.json");
// 读取超长JSON
String big100Str = readJsonFile("big100.json");
// 读取较长JSON
String big1000Str = readJsonFile("big10000.json");
Map<String,String> map = new HashMap<>();
map.put("简单数据",smallStr);
map.put("复杂数据",bigStr);
map.put("较长数据",big100Str);
map.put("超长数据",big1000Str);
// 执行次数
int n = 1;
// 循环统计执行时间
for (String name:map.keySet()) {
Log.e("TAG", "==========================" + name + "===========================");
// 计时
long start = System.currentTimeMillis();
// 测试Fastjson
for (int i = 0; i < n; i++) {
fastjsonDemo(map.get(name),name);
}
Log.e("TAG", "fastjson:" + (System.currentTimeMillis() - start));
start = System.currentTimeMillis();
// 测试Gson
for (int i = 0; i < n; i++) {
gsonDemo(map.get(name),name);
}
Log.e("TAG", "GSON:" + (System.currentTimeMillis() - start));
start = System.currentTimeMillis();
// 测试原生jsonObject
for (int i = 0; i < n; i++) {
jsonObjectDemo(map.get(name),name);
}
Log.e("TAG", "jsonObject:" + (System.currentTimeMillis() - start));
}