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

相關文章
相關標籤/搜索