Gson与FastJson比较

一. 简介和优劣

1.Google的Gson

Gson是目前功能最全的Json解析神器,Gson当初是为因应Google公司内部需求而由Google自行研发而来,但自从在2008年五月公开发布初版后已被许多公司或用户应用。Gson的应用主要为toJson与fromJson两个转换函数,无依赖,不须要例外额外的jar,可以直接跑在JDK上。
而在使用这种对象转换以前需先建立好对象的类型以及其成员才能成功的将JSON字符串成功转换成相对应的对象。java

类里面只要有get和set方法,Gson彻底能够将复杂类型的json到bean或bean到json的转换,是JSON解析的神器。算法

Gson在功能上面无可挑剔,可是性能上面比FastJson有所差距。json

2.阿里巴巴的FastJson

Fastjson是一个Java语言编写的高性能的JSON处理器,由阿里巴巴公司开发。
无依赖,不须要例外额外的jar,可以直接跑在JDK上。 FastJson在复杂类型的Bean转换Json上会出现一些问题,可能会出现引用的类型,致使Json转换出错,须要制定引用。数组

FastJson采用首创的算法,将parse的速度提高到极致,超过全部json库。安全

3. 其余

json-lib最开始的也是应用最普遍的json解析工具,json-lib 很差的地方确实是依赖于不少第三方包,对于复杂类型的转换,json-lib对于json转换成bean还有缺陷,好比一个类里面会出现另外一个类的list或者map集合,json-lib从json到bean的转换就会出现问题。json-lib在功能和性能上面都不能知足如今互联网化的需求。
相比json-lib框架,Jackson所依赖的jar包较少,简单易用而且性能也要相对高些。
并且Jackson社区相对比较活跃,更新速度也比较快。
Jackson对于复杂类型的json转换bean会出现问题,一些集合Map,List的转换出现问题。
Jackson对于复杂类型的bean转换Json,转换的json格式不是标准的Json格式框架

综上,在项目选型的时候可使用Google的Gson和阿里巴巴的FastJson两种并行使用,
若是只是功能要求,没有性能要求,可使用google的Gson,
若是有性能上面的要求可使用Gson将bean转换json确保数据的正确,使用FastJson将Json转换Bean。函数

2、基本使用方式

Gson工具

//解成对象 Fromat mFromat = new Gson().fromJson(jsonStringObject, Fromat.class); //解成对象组 LinkedList<Fromat> list = new LinkedList<MainActivity.Fromat>(); Type type = new TypeToken<LinkedList<Fromat>>(){}.getType(); list = new Gson().fromJson(jsonStringArray, type); //泛型统一封装时 须要传个 type 进来 new TypeToken<LinkedList<Fromat>>(){}.getType(); fromJson(String json, Type typeOfT) public <T> T fromJson(String json, Type typeOfT) //解成对象 Fromat mFromat = new Gson().fromJson(jsonStringObject, Fromat.class); //解成对象组 LinkedList<Fromat> list = new LinkedList<MainActivity.Fromat>(); Type type = new TypeToken<LinkedList<Fromat>>(){}.getType(); list = new Gson().fromJson(jsonStringArray, type); //泛型统一封装时 须要传个 type 进来 new TypeToken<LinkedList<Fromat>>(){}.getType(); fromJson(String json, Type typeOfT) public <T> T fromJson(String json, Type typeOfT)

fastJson性能

//解析成对象 Fromat fastjsonObject = JSON.parseObject(jsonObjectString, Fromat.class); //解析成对象组 List<Fromat> fastjsonArray = JSON.parseArray(jsonArrayString, Fromat.class); //泛型统一封装时 须要传个 type 进来 或者TypeReference 也能够也是调用的type new TypeReference<Fromat>() {} new TypeReference<Fromat>() {}.getType() public static <T> T parseObject(String input, Type clazz, Feature... features) public static <T> T parseObject(String text, TypeReference<T> type, Feature... features) //解析成对象 Fromat fastjsonObject = JSON.parseObject(jsonObjectString, Fromat.class); //解析成对象组 List<Fromat> fastjsonArray = JSON.parseArray(jsonArrayString, Fromat.class); //泛型统一封装时 须要传个 type 进来 或者TypeReference 也能够也是调用的type new TypeReference<Fromat>() {} new TypeReference<Fromat>() {}.getType() public static <T> T parseObject(String input, Type clazz, Feature... features) public static <T> T parseObject(String text, TypeReference<T> type, Feature... features)

3、细节比较

一、属性和set方法名称不一致时

如今我有这么一个Bean,属性名为firstName,可是它的set方法倒是setName(),而不是setFirstName()
下面我使用Gson与FastJson分别将这样的一个Bean转成一个Json字符串,你们猜会有什么区别?测试

 @Test public void toJson() { Bean bean = new Bean(); bean.setAge(24); bean.setName("扎巴也"); //方法是setName,属性是firstName String fastJson = JSON.toJSONString(bean); System.out.println("fastJson=" + fastJson); String gson = new Gson().toJson(bean); System.out.println("gson=" + gson); } @Test public void toJson() { Bean bean = new Bean(); bean.setAge(24); bean.setName("扎巴也"); //方法是setName,属性是firstName String fastJson = JSON.toJSONString(bean); System.out.println("fastJson=" + fastJson); String gson = new Gson().toJson(bean); System.out.println("gson=" + gson); }

输出结果:

fastJson={"age":24,"name":"扎巴也"} gson={"firstName":"扎巴也","age":24} fastJson={"age":24,"name":"扎巴也"} gson={"firstName":"扎巴也","age":24}

序列化时fastJson是按照set方法的名字来转换的,而gson则是按照属性的名字来转换的。

不信?好,咱们再来看看反序列化时会怎样?

 @Test public void fromJson() { String json = "{\"age\":24,\"name\":\"扎巴也\"}"; Bean fastjson = JSON.parseObject(json, Bean.class); System.out.println("fastJson=" + fastjson.toString()); Bean gson = new Gson().fromJson(json, Bean.class); System.out.println("gson=" + gson.toString()); } @Test public void fromJson() { String json = "{\"age\":24,\"name\":\"扎巴也\"}"; Bean fastjson = JSON.parseObject(json, Bean.class); System.out.println("fastJson=" + fastjson.toString()); Bean gson = new Gson().fromJson(json, Bean.class); System.out.println("gson=" + gson.toString()); }

输出结果:

fastJson=Bean{firstName='扎巴也', age=24} gson=Bean{firstName='null', age=24} fastJson=Bean{firstName='扎巴也', age=24} gson=Bean{firstName='null', age=24}

由于Bean类里面有name的set方法,因此fastJson解析时调用了setName,因此firstName有值
可是Bean类里面却没有name属性,因此gson解析时,firstName没有值

二、有属性,无set方法

如今我有这么一个Person,属性名为name,可是它没有name的set方法
那么,我来解析这样一个字符串时,FastJson和Gson会有什么区别呢?

{"age":24,"name":"扎巴也"} {"age":24,"name":"扎巴也"}

测试代码:

 @Test public void fromJsonNoSet() { String json = "{\"age\":24,\"name\":\"扎巴也\"}"; Person fastjson = JSON.parseObject(json, Person.class); System.out.println("fastJson=" + fastjson.toString()); Person gson = new Gson().fromJson(json, Person.class); System.out.println("gson=" + gson.toString()); } @Test public void fromJsonNoSet() { String json = "{\"age\":24,\"name\":\"扎巴也\"}"; Person fastjson = JSON.parseObject(json, Person.class); System.out.println("fastJson=" + fastjson.toString()); Person gson = new Gson().fromJson(json, Person.class); System.out.println("gson=" + gson.toString()); }

输出结果:

fastJson=Person{name='null', age=24} gson=Person{name='扎巴也', age=24} fastJson=Person{name='null', age=24} gson=Person{name='扎巴也', age=24}

由于Person没有name的set方法,因此fastJson解析的name为null

再次证实,fastJson是按照set方法的名字来转换的,而gson则是按照属性的名字来转换的。

那么,无属性,有set方法时,二者有什么区别呢?(其实没有属性的话,set方法调用了没啥做用)
测试代码:

 @Test public void fromJsonNoFiled() { String json = "{\"age\":24,\"name\":\"扎巴也\"}"; Student fastjson = JSON.parseObject(json, Student.class); System.out.println("fastJson=" + fastjson.toString()); Student gson = new Gson().fromJson(json, Student.class); System.out.println("gson=" + gson.toString()); } @Test public void fromJsonNoFiled() { String json = "{\"age\":24,\"name\":\"扎巴也\"}"; Student fastjson = JSON.parseObject(json, Student.class); System.out.println("fastJson=" + fastjson.toString()); Student gson = new Gson().fromJson(json, Student.class); System.out.println("gson=" + gson.toString()); }

输出结果:

调用了setName:扎巴也 fastJson=Student{age=24} gson=Student{age=24} 调用了setName:扎巴也 fastJson=Student{age=24} gson=Student{age=24}

fastJson调用了set方法,而gson没有调用set方法。
一样证实,fastJson是按照set方法的名字来转换的,而gson则是按照属性的名字来转换的。

三、无默认的无参构造方法

如今有这么一个Teacher类,他只有一个两个参数的构造方法,没有默认的无参构造方法,那么,我来解析这样一个字符串时,FastJson和Gson会有什么区别呢?

{"age":24,"name":"扎巴也"} {"age":24,"name":"扎巴也"}

测试代码:

 @Test public void fromJsonNoDefaultConstructor() { String json = "{\"age\":24,\"name\":\"扎巴也\"}"; Teacher gson = new Gson().fromJson(json, Teacher.class); System.out.println("gson=" + gson.toString()); Teacher fastjson = JSON.parseObject(json, Teacher.class); System.out.println("fastJson=" + fastjson.toString()); } @Test public void fromJsonNoDefaultConstructor() { String json = "{\"age\":24,\"name\":\"扎巴也\"}"; Teacher gson = new Gson().fromJson(json, Teacher.class); System.out.println("gson=" + gson.toString()); Teacher fastjson = JSON.parseObject(json, Teacher.class); System.out.println("fastJson=" + fastjson.toString()); }

这里,Gson能够正常的解析,可是,fastJson则会报错,由于没有默认的无参构造方法。
这说明了反序列化时,fastJson是经过无参构造方法来建立对象的,那么gson又是怎么建立对象的呢?(是调用了Unsafe.allocateInstance()这个native方法来建立对象的。
可是,咱们知道,这个方法直接操做内存,是不安全的,那么,若是反序列化的那个类,存在默认的无参构造方法呢?)

四、有默认的无参构造方法

 @Test public void fromJsonHasDefaultConstructor() { String json = "{\"age\":24,\"name\":\"扎巴也\"}"; Boss gson = new Gson().fromJson(json, Boss.class); System.out.println("gson=" + gson.toString()); Boss fastjson = JSON.parseObject(json, Boss.class); System.out.println("fastJson=" + fastjson.toString()); } @Test public void fromJsonHasDefaultConstructor() { String json = "{\"age\":24,\"name\":\"扎巴也\"}"; Boss gson = new Gson().fromJson(json, Boss.class); System.out.println("gson=" + gson.toString()); Boss fastjson = JSON.parseObject(json, Boss.class); System.out.println("fastJson=" + fastjson.toString()); }

gson和fastJson都调用了默认的无参构造方法.
至此,咱们能够得出结论:
有默认的无参构造方法时,gson和fastJson都会调用它来建立对象,没有默认的无参构造方法时,fastJson会直接报错!而gson则会调用Unsafe.allocateInstance()这个native方法直接在内存上建立对象。

4、Gson中使用泛型

例:JSON字符串数组
当咱们要经过Gson解析这个json时,通常有两种方式:使用数组,使用List。而List对于增删都是比较方便的,因此实际使用是仍是List比较多。

数组比较简单

Gson gson = new Gson(); String jsonArray = "[\"Android\",\"Java\",\"PHP\"]"; String[] strings = gson.fromJson(jsonArray, String[].class); Gson gson = new Gson(); String jsonArray = "[\"Android\",\"Java\",\"PHP\"]"; String[] strings = gson.fromJson(jsonArray, String[].class);

但对于List将上面的代码中的 String[].class 直接改成 List.class 是行不通的。对于Java来讲List 和List 这俩个的字节码文件只一个那就是List.class,这是Java泛型使用时要注意的问题 泛型擦除。

为了解决的上面的问题,Gson为咱们提供了TypeToken来实现对泛型的支持,因此当咱们但愿使用将以上的数据解析为List时须要这样写。

Gson gson = new Gson(); String jsonArray = "[\"Android\",\"Java\",\"PHP\"]"; String[] strings = gson.fromJson(jsonArray, String[].class); List<String> stringList = gson.fromJson(jsonArray, new TypeToken<List<String>>() {}.getType()); Gson gson = new Gson(); String jsonArray = "[\"Android\",\"Java\",\"PHP\"]"; String[] strings = gson.fromJson(jsonArray, String[].class); List<String> stringList = gson.fromJson(jsonArray, new TypeToken<List<String>>() {}.getType());

注:TypeToken的构造方法是protected修饰的,因此上面才会写成new TypeToken<List>() {}.getType() 而不是 new TypeToken<List>().getType()

参考:
https://www.jianshu.com/p/e740196225a4
https://blog.csdn.net/lckj686/article/details/51587073
https://blog.csdn.net/xiaoke815/article/details/52920405
https://www.jianshu.com/p/153111dde324

相关文章
相关标签/搜索