本文原創作者
bigsai
(同公眾號),本文以淺顯易懂的方式給大家講解自己所認知的json,如果有錯誤或者不準確地方還請大家給出指正,另外本文以關卡課程的方式在博學谷也是免費開放的,大家也可通過關卡方式學習。
誕生於JavaScript,json的前世今生
json含義
在開始之前,問個問題,什麼是json?
- a:我猜它應該是某一門高深的技術(語重心長)
- b:json這個詞為啥谷歌翻譯?是啥新詞語嘛?是不是搞錯了喲?(底氣十足)
- c:json這個我聽過,我只知道他是一種很輕量儲存結構,但具體真的不太懂(輕聲)
json它不是一個原有單詞,其實是4個單詞JavaScript Object Notation(JavaScript物件表示)的簡寫,是一種輕量級的文字資料交換格式,並且json獨立於語言(使用JavaScript語法描述物件),很多程式語言都支援json。 json 已成為當前伺服器與 web 應用之間資料傳輸的公認標準。
json誕生
問個問題,json是如何誕生的呢?
這個問題首先由於網際網路應用之間需要傳輸資料,且很多跨平臺的程式需要互動,只能採取純文字方式的互動,而xml當初就是一個選擇,但是xml規範越來越多也越來越複雜,解析效率也比較低,很多攻城獅看到xml頭都大了,可能搞了很久也搞不明白。
然後獨鍾於JavaScript的JavaScript大宗師(JavaScript之父評價)Douglas Crockford根據JavaScript的規範發明推廣了json,json格式簡單易用,且同樣可跨平臺傳出,得到廣泛的認可和傳播。就這樣,json就越來越流行了,現在已經成為主流技術之一。
(選擇題)章節練習:json是一種什麼東西呢(B)?
- A.JavaScript物件
- B.輕量級文字資料交換格式
- C.一種語言
- D.一種框架
搞清json兄弟姐妹,看清區別
json VS xml
談起json,那xml肯定是少不了對比的東西啊,沒有對比就是沒有傷害,在和json履行相同職責的文字傳輸交換格式還有json的老大哥xml(可擴充套件標記語言),在json橫空出世以前,我們們用的可都是xml進行檔案資料傳輸。
首先我們們要從定義上來看看json和xml的區別:
JSON(JavaScript Object Notation)
一種輕量級的資料交換格式,具有良好的可讀和便於快速編寫的特性。可在不同平臺之間進行資料交換。其語言習慣具備類c的習慣體系(c,c++,java等)。
XML(Extensiable Markup Language,可擴充套件標記語言)
用於標記電子檔案使其具有結構性的標記語言,可以用來標記資料、定義資料型別,是一種允許使用者對自己的標記語言進行定義的源語言。
json的橫空出世,是充分吸取借鑑了xml的優點,故json和xml有著一些相同的優點:
- 可讀性好,結構清晰
- 分層儲存(層次巢狀)
- 都可作為Ajax傳輸資料
- 都跨平臺,可作為資料傳輸格式
但json畢竟青出於藍而青於藍,肯定有著xml一些沒有的特點和優勢,例如:
- 資料格式簡單,易讀易寫,且資料都是壓縮的,檔案較小,便於傳輸。
- json解析難度較低,而xml需要迴圈遍歷DOM進行解析,效率較低。
- 服務端和客戶端可以直接使用json,便於維護。而不同客戶端解析xml可能使用不同方法。
- json 已成為當前伺服器與 web 應用之間資料傳輸的公認標準。
儘管如此,xml仍有它獨有應用領域:
- xml格式較為嚴謹,可讀性更強,更易於擴充,可以良好的做配置檔案。
- 出現較早,在各個領域有廣泛的應用,具有普遍的流行性。
當然,不是所有的json都是"特侖蘇",適合場景需要的才是最好的。但在web領域的資料傳輸,它就是王者!
(選擇題)小練習:下列哪一項是錯誤選項?(B)
- A.相同內容檔案json通常要比xml更簡潔更小。
- B.json解析起來比xml複雜很多。
- C.json和xml都是一種跨平臺文字傳輸格式。
- D.json是JavaScript Object Notation單詞的簡寫。
小小翻譯官,json的應用
json之所以很流行,是因為json有著廣泛的應用領域。主要包括與ajax結合使用的統一平臺的前端傳輸;跨平臺的資料傳輸;非關係型資料庫的文件儲存等。這些領域通過使用json使得應用效率大大提高。
前端ajax+json非同步傳輸:
json本身就起源於JavaScript,JavaScript解析處理json有天然的優勢,而在Ajax非同步載入的資料中,整體頁面已經載入過了,我們只需要在對應位置渲染真實的資料就行了,。而這部分的真實資料我們用json文字來儲存,使用JavaScript非同步向服務端請求,請求成功之後JavaScript對其渲染填充就可以了。下圖就是對前後端互動傳統方式和ajax非同步互動的簡要描述:
如果對AJAX也不熟悉?流程也看不懂,也不能明白非同步傳輸的真諦在哪裡,那好我們們以下圖這個例子來解釋一下,對於一個非常龐大的網頁部分,可以有各個模組組成,其中評論模組是我們非常小的模組,但是評論可能涉及很多條可能涉及分頁,如果我們每次為了看下一頁的評論,點選下一頁就向服務端請求整個頁面資源進行重新整理,那樣就太浪費服務端資源和頻寬了(就評論的文字變了,就要把其他模組全部渲染一遍?)
所以我們採取所謂AJAX非同步更新這個東西,也就是通過JavaScript請求下一頁的評論相關資料(用json
作為資料互動文字),JavaScript得到這串json字串中就有頁面需要的評論資訊,然後我們強大到無所不能的JavaScript將這部分重現渲染到評論模組的對應位置。
這個流程下來,我們不僅節約了頻寬,提高了響應速度,還提高了伺服器相對負載能力(每次請求需要的資源更少),提高了使用者的使用體驗,還提高了------(此處省略萬字)
跨平臺webservice:
前面提到的是前後端的互動,前提是後端同是一門程式語言、平臺,向前端提供服務。但隨著網際網路的發展,很多時候會遇到服務拆分、跨平臺等服務的需要。而跨語言跨平臺的最大障礙就是服務的交流問題。你總不至於用你電腦上的c++程式碼直接呼叫我電腦上某個java函式吧?為了解決這種問題,這時候通過restful風格的介面和json作為文字傳輸的格式就能良好的解決服務通訊問題。
例如某個公司業務太大,將服務分配給A團隊和B團隊。很多時候A可能需要進行呼叫B服務。如果A團隊全部是java,B團隊全部是php,互相喊著天下第一不肯相讓。這該怎麼辦?那麼通過json進行通訊是一種非常好的方式。流程如圖簡要所示:
非關聯式資料庫儲存(Nosql)
隨著網際網路web2.0網站的興起,傳統關聯式資料庫在處理超大規模網站和高併發方面顯得有點力不從心。而非關係型的資料庫由於它本身的特點得到非常迅速的發展,非關聯式資料庫在大規模資料下也有非常良好的讀寫效能,且資料之間無關係,無形之間就在架構層面帶來了可擴充的能力。
而有很多基於文件儲存的非關聯式資料庫採取json作為其儲存格式,其中比較著名的有:MongoDB、CouchDB、RavenDB等。儲存的內容是文件型的,這樣也有機會對某些欄位建立索引,實現關聯式資料庫的某些功能。
有些同學可能會問:既然json可以,那xml可以實現相似功能嘛?
答案是不可以,因為像xml型別的欄位,不管是查詢還是更改效率都很一般,主要原因是是DB層對xml欄位很難建高效索引,應用層又要做從字元流到dom的解析轉換。NoSQL以json方式儲存,提供了原生態的支援,在效率方面遠遠高於傳統關係型資料庫。
此外,Elasticsearch等搜尋引擎還用json和java api 提供其所有特性和功能。json在開源中介軟體的應用也越來越多!
(多選題)小練習:json常用於以下那些領域?(ABC)
- 前端Ajax非同步互動
- webservice提供介面
- 非關聯式資料庫資料儲存
拒絕四不像,json語法有要求
json語法規則
json語法是JavaScript語法的子集,而json一般也是用來傳輸物件
和陣列
。也就是json語法是JavaScript語法的一部分(滿足特定語法的JavaScript語法)。
- 資料儲存在名稱、值對中,資料由逗號分隔
- 花括號表示物件
- 中括號表示陣列
json名稱/值
json 資料的書寫格式為:"名稱":"值"
。
對應JavaScript的概念就是:名稱="值"
但json的格式和JavaScript物件格式還是有所區別:
- JavaScript物件的名稱可以不加引號,也可以單引號,也可以雙引號,但json字串的名稱只能加雙引號的字元表示。
- JavaScript物件的鍵值可以是除json值之外還可以是函式等其他型別資料,而json字串的值對只能是數字、字串(要雙引號)、邏輯值、物件(加大括號)、陣列(中括號)、null。
json物件
json有兩種表示結構—物件和陣列,通過著兩種表示結構可以表示更復雜的結構。對比java的話json陣列和json物件就好比java的列表/陣列(Object型別)和物件(Map)一樣的關係。並且很多情況其物件值可能相互巢狀多層,對物件中存在物件,物件中存在陣列,陣列中存在物件…下面這張圖能夠一定程度反應json物件和陣列的關係:
json物件很容易理解,它代表一個實體,這個實體有一些其他的屬性,這些屬性可能是數字、字串(要雙引號)、邏輯值、物件(加大括號)、陣列(中括號)、null。如果從java語言來看他就是對應一個實體類或者一個Map,其中有一些用鍵值的方式描述名稱和值。
var a = {"name":"bigsai" , "sex":"man","school":{"name":"博學谷","localtion":"Bei Jing"}};
取值:可以通過(.)或者([])進行取值,例如a.name(a.sex)
和a["name"](a["sex"])
,程式碼解釋如下:
物件套物件:可以通過(.)或者([])進行取值。程式碼解釋如下:
遍歷:可以用 for - in 進行物件遍歷。程式碼解釋如下:
修改:可以使用(.)或者([])進行修改物件的值。示例程式碼如下:
刪除:可以通過delete關鍵詞刪除json物件屬性值。示例程式碼如下:
完整程式碼截圖為:
附上程式碼:
var a = {"name":"bigsai" , "sex":"man","school":{"name":"博學谷","localtion":"Bei Jing"}};
a.name+" "+a["name"]
a.school
a["school"].name
for (key in a){//遍歷物件
console.log(key+" "+a[key]);}
a.name="saisai"
a["sex"]="woman"
a
delete a["school"]
a
json陣列
學習完json物件,那麼json陣列的學習就容易的多了。json陣列與json物件有一些區別,json陣列用中括號表示([]
),各個值用逗號(,
)分隔,並且陣列值需要是json合法資料型別(字串, 數字, 物件, 陣列, 布林值或 null).
var names=["bigsai","bigpian","bigbig"];//json陣列
var students=[{"name":"bigsai","high":180},{"name":"bigpian","high":165},{"name":"Yao Ming","high":226}];//物件套陣列
取值:可以通過中括號([]
)進行取值,例如names[0]
或names["0"]
,示例程式碼如下:
在這裡插入圖片描述
陣列套物件:取值到物件後遵從物件的語法。示例程式碼如下:
遍歷:可以用 for - in 或者for 對json陣列進行遍歷。示例程式碼如下:
修改:可以使用([]
)索引號進行修改陣列。示例程式碼如下:
刪除:可以通過delete關鍵詞刪除json陣列中的專案。示例程式碼如下:
完整json陣列示例程式碼如下:
附上原始碼:
var names=["bigsai","bigpian","bigbig"];//json陣列
var students=[{"name":"bigsai","high":180},{"name":"bigpian","high":165},{"name":"Yao Ming","high":226}];//物件套陣列
names["0"]+" "+names[0]//json陣列取值
students[2]["name"]+" 身高:"+students[2].high//json陣列套物件(物件套陣列同理)
for (i in names){ console.log(names[i]); }//for in 遍歷
for (i=0;i<names.length;i++){console.log(names[i]);}
names[0]="bigsai666";
delete names[0];
names
JavaScript物件 VS json物件 VS json字串
在JavaScript中談到json,很多人會對JavaScript物件、json物件、json字串混淆和概念不清晰,我們可以舉個例子來一起看一下:
var a1={ name:"bigsai" , sex:"man" };//JavaScript物件
var a2={'name':'bigsai' , 'sex':'man'};//JavaScript物件
var a3={"name":"bigsai" , "sex":"man"};//滿足json格式的JavaScript物件
var a4='{"name":"bigsai" , "sex":"man"}';//json字串
總的來說:
-
JavaScript物件:除了字串、數字、true、false、null和undefined之外,JavaScript中的值都是物件。
-
json物件:這個說法其實不太準確,沒有單獨的json物件,我們常說的json物件它實質是滿足json格式要求的JavaScript物件。如上a3物件。
-
json字串,滿足json語法格式的字串(json是一種資料格式),有時也稱json串。
在這裡多說幾句,你可能會對json物件還是有點不夠清晰,你可能在其他地方也會遇到json物件。首先,json是一種資料格式,而json有物件和陣列兩種具體表現格式。
- 當你直接說json物件,json陣列的時候。它其實就是直接談json的兩種表示結構。它主要體現的是結構。
- 在JavaScript中,我們通常說的json物件,json陣列通常代指滿足json格式的JavaScript物件,JavaScript陣列。
- 在java中我們有時也說json物件,json陣列,這個其實就是第三方工具包基於json規範封裝的JSONObject、JSONArray類。
總的來說,我們通常說的json物件、json陣列它實質是一種資料格式。但同在在不同語言中滿足這種格式要求的物件、陣列我們會稱其為json物件、json陣列。
(選擇題)小練習:下列哪一項是滿足json格式的JavaScript物件?(D)
- A. { name : "博學谷" , value : "very well" };
- B. { 'name' : "博學谷" , 'value' : "very well" };
- C. { name : "張三" , age : "18" };
- D. { "name" : "李四" , "age" : 25 };
小結
本章小結:大家可以發現json的語法規則還是相對簡單的,對於json語法格式,大家要謹記json的資料名稱只能是帶雙引號(""
)的字串,而json物件的值要謹記有哪幾種滿足的型別。對於json物件和json陣列來說,是json的兩種表示結構,而json的靈活性也允許兩種型別的相互巢狀,可以表示更為複雜的結構。
(單選題)既然大家和我一起學了json物件、陣列以及一些基本語法,下面考考大家,json物件的值不可以是下面哪種型別呢?(D)
- 字串
- 數字
- json物件/json陣列
- 函式
谷歌Gson,精簡而強大
序列化/反序列化介紹
前面我們學習了json的一些概念和基礎語法,也知道了json起身於JavaScript,在很多語言如python中得到較好的支援,但也有很多語言從語言本身來說是不支援json的(就比如我們們強大的java)。這雖然是一大障礙但並不阻止我們在java這門語言中使用json。我們可以通過新增一些工具包使得java支援json處理。
這些工具包能夠將json字串轉換成java物件,從而在Java中使用。反過來也可以將java物件轉換成json字串,從而更廣泛地用在其他地方。將Java物件到Json字串的過程我們稱為Serialization序列化,將Json字串轉換成Java物件的過程我們稱為Deserialization反序列化。
如果理解起來容易混淆,那麼可以藉助下面這張圖進行結合記憶:我們們從java角度來看,java物件需要從一個整體物件拆分成一個個碎片按序列往json字串中寫入,這就是一個序列化過程。而json字串的一個個碎片反過來重新組裝成一個完整的java物件這個過程就是反序列化。
對於json本身來說是不復雜的,但是在java中如果程式設計師直接操作json字串那是一件非常麻煩和複雜的事情,不少優秀的程式設計師/團隊/公司努力研究,將他們經驗和智慧開源出來供大家使用,在其中,Gson/fastjson/Jackson要更流行一些。我們們一個個瞭解一下。
Gson介紹
在學習之前,你知道什麼是Gson嗎?
Gson是谷歌開源的一個Java庫,可用於將Java物件轉換為(序列化)其JSON表示形式。它還可以用於將JSON字串轉換為(反序列化)等效的Java物件。Gson可以處理任意Java物件,包括沒有原始碼的現有物件。下圖為Gson在github主頁一些資訊。
在這裡
每種json工具包都有它自己的優點和長處,對於Gson來說,有以下幾點特點:
- 提供簡單的toJson()和fromJson()方法,將Java物件轉換成json字串,反之亦然
- 允許將現有的不可修改物件與JSON相互轉換
- Java泛型的廣泛支援
- 允許物件的自定義表示
- 支援任意複雜的物件(具有深層次的繼承層次結構、泛型等)
Gson實戰
下面和大家一起動手進行Gson實戰,Gson的功能比較強大,在這裡呢和大家一起實現一些基礎和常用的使用。
首先建立一個java專案(Maven),要引入Gson的Maven依賴或jar包,其Maven依賴為:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
有了Gson的依賴之後,那麼實現Java物件與Json的轉化也就很簡單啦,大體就是分為兩步啦:
- 首先建立Gson物件,這裡可以直接new 或者使用GsonBuilder進行建立,如果使用直接new的方式建立Gson物件是使用預設的配置;而使用GsonBuilder首先要建立GsonBuilder,然後GsonBuilder呼叫一些配置方法,然後呼叫create()方法構建Gson物件。
- 然後通過Gson物件的toJson(),fromJson()方法進行序列化和反序列化操作。
javaBean與json字串互相轉換:
首先建立一個student物件
public class student {
private String name;
private int age;
private String sex;
public student(String name, int age, String sex) {//構造方法
this.name = name;
this.age = age;
this.sex = sex;
}
@Override
public String toString() {//重寫toString方法
return "student{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
public String getName() {//獲取name字串
return name;
}
public void setName(String name) {//設定物件name
this.name = name;
}
public int getAge() {//獲取年齡int
return age;
}
public void setAge(int age) {//設定年齡值
this.age = age;
}
public String getSex() {//獲取性別
return sex;
}
public void setSex(String sex) {//設定性別
this.sex = sex;
}
}
其次,在測試中進行JavaBean(student)與json字串的轉換。主要通過toJson()和fromJson()進行序列化和反序列化操作。toJson,直譯過來就是“到達json”,所以是將java物件轉成json字串,也就是序列化。fromJson,直譯過來就是“來自json”,所以是將json字串轉化為java物件,也就是反序列化。
//Gson gson= new GsonBuilder().create();//可以自定義一些配置
Gson gson=new Gson();//建立json物件
//java物件 to json
student stu=new student("Ben",22,"man");
String stustr=gson.toJson(stu,student.class);//json轉為string
System.out.println("student物件為"+stu.toString());
System.out.println("轉化為json字串:"+stustr);
//json to java物件
///滿足條件的json字串{"name":"tony","age":32,"sex":"woman"}
String jsonstr="{\"name\":\"tony\"," +
"\"age\":32," +
"\"sex\":\"woman\"}";
student jsonstrobject=gson.fromJson(jsonstr,student.class);//轉換為student物件
System.out.println("json字串為"+jsonstr);
System.out.println("轉化為student物件為:"+jsonstrobject.toString());
執行的結果為:
java集合與json字串互相轉化:
在實際開發中,我們很可能遇到的並不是javaBean與json字串的直接轉化,而是集合之類的轉化工作,java集合種類繁多。在此,我們實現Map、List、String陣列的序列化和反序列化操作。
在進行序列化操作時,我們首先建立Map<String,String>
,List<Object>
,String[]
物件然後填充一定資料以便進行序列化和反序列化操作。
Gson gson=new Gson();//建立json物件
//Map
Map<String,String>map=new HashMap<>();//Map
map.put("博學谷","666");map.put("小老弟","要加油");
//List
List<Object>list=new ArrayList<>();//List型別
list.add("hello");list.add("world");list.add(map);
//String[]
String []str={"Hello","World"};//String
String mapTojsonStr=gson.toJson(map);//{"小老弟":"要加油","博學谷":"666"}
String listTojsonStr=gson.toJson(list);//["hello","world",{"小老弟":"要加油","博學谷":"666"}]
String strTojsonStr=gson.toJson(str);//["Hello","World"]
System.out.println("Map轉為json:"+mapTojsonStr);
System.out.println("List轉為json:"+listTojsonStr);
System.out.println("String[]轉為json:"+strTojsonStr);
執行的結果為:
我們將這些字串複製到新的程式碼域進行反序列化操作,在反序列化時候,我們會用到fromJson()這個函式時,有兩種我們常用的構造方式fromJson(String json, Class<T> classOfT)
和fromJson(String json, Type typeOfT)
,如果遇到泛型等型別時候需要藉助 TypeToken來獲取物件型別。
Gson gson=new Gson();//建立json物件
String mapTojsonStr="{\"小老弟\":\"要加油\",\"博學谷\":\"666\"}";//{"小老弟":"要加油","博學谷":"666"}
String listTojsonStr="[\"hello\",\"world\",{\"小老弟\":\"要加油\",\"博學谷\":\"666\"}]";//["hello","world",{"小老弟":"要加油","博學谷":"666"}]
String strTojsonStr="[\"Hello\",\"World\"]";//["Hello","World"]
//方式一方便簡潔(這裡避免衝突註釋掉)
//Map<String,String>map1=gson.fromJson(mapTojsonStr,Map.class);
//方式二可以獲取泛型等資料型別
Map<String,String>map1=gson.fromJson(mapTojsonStr,new TypeToken<Map<String,String>>(){}.getType());
List<Object>list=gson.fromJson(listTojsonStr,List.class);
Map<String,String>map2=(Map<String,String>)list.get(2);
String str[]=gson.fromJson(strTojsonStr,String[].class);
System.out.println("json轉Map:"+map1.toString());
System.out.println("json轉List"+list.toString());
System.out.println("map1和map2是否相等:"+map2.equals(map2));//相等
System.out.println("String[]:"+ Arrays.toString(str));
輸出結果為:
上面只是介紹了java物件與json字串的轉換,實際上Gson不僅入手容易,還有其他非常強大的功能,在使用Gson開發中除了java物件和json字串的轉換,我們經常也會對JsonObject直接進行操作(類似JavaScript中操作json串一樣),這裡你需要了解學習Gson封裝的JsonEelement,JsonObject,JsonArray,JsonPrimitive,JsonNull等資料型別。
不同的資料型別有各自的使用場景,下面給大家介紹下各個資料型別之間的區別與聯絡:
- JsonElement:表示Json元素的類。 它可以是JsonObject,JsonArray,JsonPrimitive或JsonNull。這個你可以理解一下java中List(Arraylist,LinkedList),Map(HashMap.TreeMap,ConcurrentHashMap)等聯絡。也可以理解為Object的類與其他類的關係。
- JsonObject:表示Json中物件型別的類。 物件由名稱-值對組成,其中名稱是字串,而值是任何其他型別的JsonElement。
- JsonArray: 表示Json中陣列型別的類。 陣列是JsonElement的列表,每個JsonElement的型別可以不同。 這是一個有序列表,意味著保留新增元素的順序。
- JsonPrimitive:表示Json基本值的類。 基本值可以是String,Java基本型別或Java基本型別的包裝類。
- JsonNull:表示Json空值的類。
對於這些資料型別,你可能會問:為啥json字串已經可以和java物件互相轉了,還需要這些資料型別呢?
答案是這些資料型別讓java中多一種可以處理json格式資料的方式。一方面讓java處理json格式資料更加靈活,另一方面在某些場景下這樣直接操作JsonObject、JsonArray等能夠簡化工作流程。
其實這些資料型別就是相當於用java的資料結構構造一個json的資料結構和方法(java本身不直接支援json),讓我們能夠直接使用和操作json。
從上圖可以看得出,上面這些資料結構也是根據java的一些資料結構作為儲存,然後寫一些操作函式,封裝一些方法。當然,JsonObject也可以通過Gson的toJson()和fromJson()方法靈活轉成字串和java物件。
有很多時候我們後臺處理接受到的是一個json字串,可能其內部結構也很複雜,如果我們將其轉成java物件可能要編寫java對應的實體,但是如果直接操作json物件可能就省下一些操作和流程,如果只需增刪改其中很小的一部分,那麼這種選擇也是一種不錯的方案。當然具體的使用方法和方案還需要根據具體的業務來判斷!
(多選)既然學習了Gson,那麼就來考考大家到底有沒有真的掌握Gson的關鍵函式,仔細思考哦,這題有點狠,一錯俱錯呦:(AD)
- A.函式 toJson() 是將物件轉成json字串。
- B.函式 toJson() 是將json字串轉成物件。
- C.函式fromJson() 是將物件轉成json字串。
- D.函式fromJson() 是將json字串轉成物件。
飛人fastjson,阿里的"黑科技"
fastjson介紹
除了谷歌的Gson,我們們國內也有一款非常強大的java序列化工具包—fastjson。下圖為fastjson在github的主頁:
在
學習fastjson之前同樣問:什麼是fastjson?
- fastjson是阿里巴巴的開源JSON解析庫,它可以解析JSON格式的字串,支援將Java Bean序列化為JSON字串,也可以從JSON字串反序列化到JavaBean。
除了是國內阿里開源的,fastjson還有優異的效能,fastjson的優點如下:
- 速度快:fastjson相對其他JSON庫的特點是快,從2011年fastjson釋出1.1.x版本之後,其效能從未被其他Java實現的JSON庫超越。
- 使用廣泛、測試完備。在阿里內部有廣泛的應用。
- 使用簡單、功能完備。支援泛型、複雜型別等。
fastjson實戰
下面帶大家實戰fastjson,同樣首先我們需要引入依賴,下載jar包引入或者maven的依賴。
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.70</version>
</dependency>
fastjson與Gson雖然大體相似但有所區別,fastjson自己也有實現的JSONObject,JSONArray類,前面在Gson中介紹過此類的作用我們在進行轉換時候就把JSONObject加入進行轉換。在fastjson主要提供以下三個類:
(1)JSON:fastJson的解析器,用於JSON格式字串與JSON物件及javaBean之間的轉換。
(2)JSONObject:fastJson提供的json物件。
(3)JSONArray:fastJson提供json陣列物件。
json字串、JSONObject及JavaBean之間的相互轉換
首先,我們同樣定義一個student類(同Gson的student類)
public class student {
private String name;
private int age;
private String sex;
public student(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
//get set方法
}
在測試程式碼中,我們分別編寫一些程式碼實現三者的相互轉換,但JSONObject、JSONArrray、JSON以及fastjson仍然有很多方法功能在這裡就無法進行很詳細的展示了:
//物件轉json字串,JSONObject
student student1=new student("xiaoming",5,"man");
String jsonstr1= JSON.toJSONString(student1);//物件轉json字串
JSONObject jsonObject1=(JSONObject) JSON.toJSON(student1);//物件轉JSONObject
System.out.println(jsonObject1.toString());
System.out.println(jsonstr1+"\n");
//json字串轉java物件,JSONObject
String jsonstr2="{\"age\":5,\"name\":\"xiaoming\",\"sex\":\"man\"}";
JSONObject jsonObject2=JSON.parseObject(jsonstr2);//json字串轉JSONObject物件
student student2 = JSON.parseObject(jsonstr2,student.class);//json字串轉java物件
System.out.println(jsonObject2.toString());
System.out.println(student2.toString()+"\n");
//JSONObject 轉java物件,json字串
JSONObject jsonObject3=jsonObject2;
jsonObject3.put("age",18);//修改年齡
student student3=jsonObject3.toJavaObject(student.class);//JSONObject轉java物件
String jsonstr3=jsonObject3.toJSONString();//JSONObject轉json字串
String name=jsonObject3.getString("name");//JSONObject取值
int age=jsonObject3.getInteger("age");
String sex=jsonObject3.getString("sex");
System.out.println("姓名"+name+" 年齡"+age+" 性別"+sex);
System.out.println(student3.toString());
System.out.println(jsonstr3+"\n");
對應輸出的結果與預期一致:
json字串、JSONObject及Java集合相互轉換
上面進行了基於javabean的一些轉換和操作,下面我們進行對java集合的一些轉化實戰。看看fastjson又是以什麼樣的引數進行的。java的Map是常用集合之一,我們們先看看Map的相關轉化:
//map的相關轉化
Map<String,String>map1=new HashMap<>();
map1.put("name","xiaoming");map1.put("sex","woman");
String jsonstr=JSON.toJSONString(map1);//Map轉json字串
JSONObject jsonObject=(JSONObject) JSON.toJSON(map1);//Map轉json物件
System.out.println(jsonstr);
System.out.println(jsonObject.toString());
//Map<String,String>map2=JSON.parseObject(jsonstr,Map.class);//方式一
Map<String,String>map2=JSON.parseObject(jsonstr,new TypeReference<Map<String, String>>(){});//方式二json字串轉Map
Map<String,String>map3=jsonObject.toJavaObject( new TypeReference<Map<String, String>>(){});//JSONObject
System.out.println(map2.toString());
System.out.println(map3.toString());
控制檯的輸出為:
此外,List同樣也是java中使用較多的集合之一,我們們可以看下它的相關轉化:
//List相關轉化
List<Map<String,String>>list1=new ArrayList<>();//集合
Map<String,String>map1=new HashMap<>();
map1.put("name","map1");
Map<String,String>map2=new HashMap<>();
map1.put("name","map2");map2.put("sex","man");
list1.add(map1);list1.add(map2);
String jsonstr=JSON.toJSONString(list1);//list轉json字串
JSONArray jsonArray =(JSONArray) JSON.toJSON(list1);//list轉jsonArray
JSONObject jsonObject=jsonArray.getJSONObject(0);
System.out.println(jsonstr);
System.out.println(jsonArray+" "+jsonArray.get(0));
//json 字串轉list
List<Map<String,String>>list2=JSON.parseObject(jsonstr,new TypeReference<ArrayList<Map<String,String>>>(){});
//List<student>list3=JSON.parseArray("",student.class);//普通list的轉換方式
System.out.println(list2.get(0).equals(map1)+" "+list2.get(1).equals(map2));//如果相等則證明成功序列化
System.out.println(list2.toString());
得到輸出結果為:
不難看的出,fastjson在入門還是非常簡單的。並且和Gson有很多相似之處,在Api的設計方面,Gson需要一個Gson物件來進行相關操作,而fastjson的JSON、JSONObject、JSONArray定義了很多靜態的方法可以直接使用。同時兩者的反序列化的TypeToken(Gson)和TypeReference(fastjson)有異曲同工之妙。
這兩者在開發過程中使用很多,各有優劣,並且這裡只是裡面很小的一部分內容,要想深入學習還需要了解官方全面API才行(Gson官方API,fastjson官方文件)。但是對於fastjson來說,有些地方可能存在一些漏洞和不穩定因素,但是阿里很快就進行修復。所以在實際使用中要考慮fastjson的安全性。
(習題)介紹完我們們國內開源的科技—fastjson,那麼我來看看對fastjson掌握程度如何,考考大家:下面哪個不是fastjson的類(D)
- A.JSON
- B.JSONObject
- C.JSONArray
- D.JsonElement
備受開源認可,Jackson亦是真王者
Jackson介紹
最後我們們介紹的就是當前更為成熟一點的jackson。jackson 是一個能夠將java物件序列化為json字串,也能夠將json字串反序列化為java物件的框架。下圖為jackson在github主頁情況:
其實jackson的應用非常廣泛,在這裡我們簡單瞭解以下jackson然後對比分析三個json工具包的異同,對於jackson來說,擁有以下幾點優勢:
- 出師較早,國際流行度較高,且社群學習內容較為豐富。
- 安全穩定,是很多開源框架的內建序列化框架(例如Springmvc)。
- 解析大的json檔案效率較高,佔用記憶體較少,效能比較好。
- 擁有靈活的API,可以很容易的擴充和定製。
jackson實戰
下面帶大家實戰jackson,在Gson和fastjson使用時只需引用一個jar,而jackson卻不是將所有全部整合到一個jar內,而是分成了多個不同的模組(不同模組具有不同功能),我們們首先引入jackson的依賴:
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.11.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.11.0</version>
</dependency>
有了jackson依賴之後,我們就可以進行實戰了,在jackson中有三種方式操作json:
- 流式API - 使用 Stream(流) 的方式對 Json 的每一個組成部分進行最細粒度的控制,JsonParser 讀取資料,JsonGenerator 寫入資料。(json streaming 流式計算,開銷最低,讀寫最快)
- 樹模型 - 將 JSON 檔案在記憶體裡以樹的形式表示,通過 JsonNode 處理單個Json節點,類似於 XML 的 DOM 解析器。(數模型Json檔案在記憶體裡以樹形式表示 ObjectMapper構建JsonNode 節點樹 最靈活)
- databind 模組 - ObjectMapper 讀/寫 JSON ,是 序列化與反序列化 json 最方便的方式。 (本篇實戰採用的方法)
javaBean與json字串相互轉換
對於javaBean,我們建立student類(注意使用jackson的類必須有空參構造器):
public class student {
private String name;
private int age;
private String sex;
public student(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public student(){}//空參構造器
//get set方法 toString方法
}
在測試程式碼中,首先建立一個ObjectMapper物件,序列化和反序列化都需要它。然後根據writeValueAsString()這個函式就可以把java物件轉成json字串(序列化)。而json字串通過readValue()就可以將json字串轉化為java物件(反序列化)。程式碼的展示如下:
//建立 ObjectMapper物件
ObjectMapper mapper=new ObjectMapper();
//序列化的實體類
student stubigsai=new student("bigsai",6,"man");
//writeValueAsString()方法進行序列化
String stubigsaistr=mapper.writeValueAsString(stubigsai);
System.out.println(stubigsaistr+"\n");
//反序列化的json字串
String stuxiaohongstr="{\"name\":\"xiaohong\",\"age\":8,\"sex\":\"woman\"}";
//readValue()方法進行反序列化
student stuxiaohong= mapper.readValue(stuxiaohongstr,student.class);
System.out.println(stuxiaohong.toString());
對於上述程式碼執行結果為:
java集合與json字串相互轉換
除了javaBean和json字串轉換外,java集合和json字串的轉換也很簡單,我們這裡就只演示java的Map與json字串相互轉化了,其流程與上述的javaBean和json互轉有點類似。需要注意的是從json轉換為Map物件(或其他泛型物件)的時候,由於Java的型別擦除,有些無法直接正確轉換的型別需要我們手動用new TypeReference給出,例項程式碼如下:
//建立 ObjectMapper實體類
ObjectMapper mapper=new ObjectMapper();
//需要序列化的Map和List
Map<String,Object>map1=new HashMap<>();
map1.put("博學谷","666");map1.put("bigsai",666);//注意兩個666型別不同
map1.put("string",new String[]{"bigsai", "博學谷"});
//序列化結果
String map1str=mapper.writeValueAsString(map1);
System.out.println(map1str+"\n");
//方式一反序列化結果
Map<String,Object>m1=mapper.readValue(map1str,Map.class);
//方式二TypeReference指定反序列化型別(適合泛型和複雜型別)
Map<String,Object>m2=mapper.readValue(map1str, new TypeReference<Map<String, Object>>() {});
System.out.println(m1.toString());
System.out.println(m2.toString());
執行結果為:
在這裡插入圖片描述
看完例項,你是不是發現:哇,原來三者有很相似的之處啊,是的,一個優秀的開源框架不光光要考慮其功能、效能,其易用性、對使用者友好程度、官方文件等也是非常重要的指標!當然,這裡僅僅是jackson功能的九牛一毛,更詳細深入的學習需要到jackson官方文件去查閱。
Gson VS fastjson VS jackson
現在三種java的序列化/反序列化json框架都已經介紹啦。三者都是非常優秀的框架,這是毋庸置疑的,但是一對比,它就有一些傷害啊(嚶嚶嚶)。
名稱 | Gson | fastjson | Jackson |
---|---|---|---|
社群生態 | 較好 | 一般 | 較好 |
易用性 | 易用 | 易用 | 一般 |
小檔案速度 | 最快 | 較快 | 較慢 |
大檔案速度 | 較慢 | 較快 | 較快 |
穩定性 | 穩定 | 一般 | 穩定 |
安裝包大小 | 非常小 | 較小 | 一般 |
綜上所述來說:
Gson:輕便簡潔,適合中小json檔案的解析。在大json檔案上效率略差,且其功能比較全面,生態較好。
jackson:處理大檔案速度快一些,且比fastjson穩定一些。生態較好。
fastjson:速度較快,但經常爆出安全問題。生態一般,主要國內使用。
對選取哪個json框架主要根據自己的需要,如果是測試或者比較簡單個人使用,推薦Gson和fastjson上手比較容易。如果是需要上線,那麼fastjson得慎用,可能某些資料會序列化失敗。
在介紹完的最後,偷偷讚揚一下我們們fastjson主要貢獻者溫少
,不僅是fastjson開源者溫少也是另一開源框架主要貢獻者—druid(阿里資料庫連線池),所以這位作者大大是非常努力,將自己奉獻給了開源的事業中,服務更多的人,點贊!!! 希望未來的我們,也能像溫少那樣有所作為!加油!
在這裡,本篇對json得介紹、json語法使用以及Gson/fastjson/jackson的一些實戰的介紹就此已經完畢了,json很容易,但json也可能很複雜,這要取決你具體業務的使用和需求,希望在日後的日子裡,能夠對json的理解和應用能夠有更深一步的認知!加油,我們下次再見!
(單選)既然對比完Gson,fastjson,Jackson,那麼小老弟妹們,俺來考考你對三者認識咋樣,那麼問題來了,你給我看看下面那個是錯的呢?(B)
- A.Gson體積較小,但功能豐富強大,社群生態完整。處理小檔案效率較高。
- B.fastjson速度較快,在國內外都比較流行,且社群生態較好。
- C.jackson廣泛應用於開源框架,穩定且效率較高,流行度和認可度最高。
- D.Gson是谷歌開源的,fastjson是阿里開源的,Jackson是fastXML團隊開源的。
小試牛刀
上面講了那麼多,對於我們來說掌握java中操作json很重要,那麼我們們動手進行一個轉換小案例。這裡我們們要求用Gson,fastjson將下面物件進行轉化:
javaBean轉json字串
假設我們有個teacher 類有name和age兩個屬性。
public class teacher {
private String name;
private int age;
//省略get set 以及建構函式
}
首先我們有一個物件
teacher teachersai=new teacher("bigsai",22);
大家想一下這個物件的json格式的字串會是什麼樣的呢?
沒錯,答案就是這樣的:
{"name":"bigsai","age":22}
如果是Gson,我們是這樣操作的:
Gson gson=new Gson();
String teacherstr=gson.toJson(teachersai);
System.out.println(teacherstr);//{"name":"bigsai","age":22}
而如果是fastjson,它又會是怎樣的呢?
String teacherstr=JSON.toJSONString(teachersai);
System.out.println(teacherstr);//{"name":"bigsai","age":22}
這樣就完成java物件轉成json字串啦,是不是非常簡單,因為fastjson將JSON中的很多方法寫成靜態static所以我們連這個物件都不需要建立。
json字串轉javaBean
上面我們們輕輕鬆鬆的就可以將javaBean轉成json字串,下面如果我們們有這麼一個字串需要轉成java的teacher物件,需要怎麼搞呢?
String teacherpian="{\"name\":\"bigpian\",\"age\":21}";//{"name":"bigpian","age":21}
那麼建立完Gson物件只需一行程式碼就搞定:
Gson gson=new Gson();
teacher teacherp=gson.fromJson(teacherpian,teacher.class);
同理,我們們fastjson也是一行程式碼搞定:
teacher teacherp=JSON.parseObject(teacherpian,teacher.class);
是不是很容易呢?當然如果細心好學的你肯定會發現還有其他的寫法啦,修行靠個人啦,更多的用法肯定還需要自己去挖掘啦!
本文總結
輕鬆愉快的json介紹課程到這裡就結束了,通過本節課程,你瞭解了json的概念,分清了json和xml的異同點,也知道了json在web領域和非關聯式資料庫的那些應用。通過系列介紹、比較、結合實際場景相信你對json的認識肯定都是非常清晰。
緊接著文章又介紹了json的語法規則以及在java中操作json的實戰操作,學習和比較了Gson、fastjson、jackson的應用以及他們之間的區別點,相信你也掌握了在java語言中json的實戰能力,且能夠根據自己需求靈活使用哪種框架,並深入的研究下去。
json是web技術進步與發展的產物,它是一種資料交換格式。它幾乎是前後端程式設計師不可避免的技術點,希望大家在日後能夠多多回顧課程,結合其他教材文字等,將json 從立地到成佛!加油,我們下次再會!
在這裡插入圖片描述