本文原创作者 bigsai(同公众号),本文以浅显易懂的方式给大家讲解自己所认知的json,如果有错误或者不准确地方还请大家给出指正,另外本文以关卡课程的方式在博学谷也是免费开放的,大家也可通过关卡方式学习。

诞生于JavaScript,json的前世今生

json含义

在开始之前,问个问题,什么是json?

  • a:我猜它应该是某一门高深的技术(语重心长)
  • b:json这个词为啥谷歌翻译?是啥新词语嘛?是不是搞错了哟?(底气十足)

9499c82a5e4e0d5b8663116d9929e83c.png
  • c:json这个我听过,我只知道他是一种很轻量存储结构,但具体真的不太懂(轻声)

json它不是一个原有单词,其实是4个单词JavaScript Object Notation(JavaScript对象表示)的简写,是一种轻量级的文本数据交换格式,并且json独立于语言(使用JavaScript语法描述对象),很多编程语言都支持json。 json 已成为当前服务器与 web 应用之间数据传输的公认标准。

json诞生

问个问题,json是如何诞生的呢?

这个问题首先由于互联网应用之间需要传输数据,且很多跨平台的程序需要交互,只能采取纯文本方式的交互,而xml当初就是一个选择,但是xml规范越来越多也越来越复杂,解析效率也比较低,很多攻城狮看到xml头都大了,可能搞了很久也搞不明白。

a395cb308939d33ce6c42da9c3154e0f.png

然后独钟于JavaScript的JavaScript大宗师(JavaScript之父评价)Douglas Crockford根据JavaScript的规范发明推广了json,json格式简单易用,且同样可跨平台传出,得到广泛的认可和传播。就这样,json就越来越流行了,现在已经成为主流技术之一。

5104cd0bf636d7a14c762909309308b9.png

(选择题)章节练习: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格式较为严谨,可读性更强,更易于拓展,可以良好的做配置文件。
  • 出现较早,在各个领域有广泛的应用,具有普遍的流行性。

05940dac3d1fb89cd4c6d7c280bc2e43.png

当然,不是所有的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异步交互的简要描述:

f74a5d2a306bbc8bdd4e13e6fb352ab2.png

如果对AJAX也不熟悉?流程也看不懂,也不能明白异步传输的真谛在哪里,那好咱们以下图这个例子来解释一下,对于一个非常庞大的网页部分,可以有各个模块组成,其中评论模块是我们非常小的模块,但是评论可能涉及很多条可能涉及分页,如果我们每次为了看下一页的评论,点击下一页就向服务端请求整个页面资源进行刷新,那样就太浪费服务端资源和带宽了(就评论的文本变了,就要把其他模块全部渲染一遍?)

9f8cc6778bd036a82dd5bbe666d45557.png

所以我们采取所谓AJAX异步更新这个东西,也就是通过JavaScript请求下一页的评论相关数据(用json作为数据交互文本),JavaScript得到这串json字符串中就有页面需要的评论信息,然后我们强大到无所不能的JavaScript将这部分重现渲染到评论模块的对应位置。

这个流程下来,我们不仅节约了带宽,提高了响应速度,还提高了服务器相对负载能力(每次请求需要的资源更少),提高了用户的使用体验,还提高了------(此处省略万字)

跨平台webservice:

前面提到的是前后端的交互,前提是后端同是一门编程语言、平台,向前端提供服务。但随着互联网的发展,很多时候会遇到服务拆分、跨平台等服务的需要。而跨语言跨平台的最大障碍就是服务的交流问题。你总不至于用你电脑上的c++代码直接调用我电脑上某个java函数吧?为了解决这种问题,这时候通过restful风格的接口和json作为文本传输的格式就能良好的解决服务通信问题。

例如某个公司业务太大,将服务分配给A团队B团队。很多时候A可能需要进行调用B服务。如果A团队全部是java,B团队全部是php,互相喊着天下第一不肯相让。这该怎么办?那么通过json进行通信是一种非常好的方式。流程如图简要所示:

f7df836fc72cf982e12c4d6d3b94b441.png

非关系数据库存储(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对象和数组的关系:

ddec08f8b191168e5934659efb6e990d.png

json对象很容易理解,它代表一个实体,这个实体有一些其他的属性,这些属性可能是数字、字符串(要双引号)、逻辑值、对象(加大括号)、数组(中括号)、null。如果从java语言来看他就是对应一个实体类或者一个Map,其中有一些用键值的方式描述名称和值。

var a = {"name":"bigsai" , "sex":"man","school":{"name":"博学谷","localtion":"Bei Jing"}};

取值:可以通过(.)或者([])进行取值,例如a.name(a.sex)a["name"](a["sex"]),代码解释如下:

fe12545270f045772f16f072801fd7a5.png

对象套对象:可以通过(.)或者([])进行取值。代码解释如下:

5f97405aa771f4dba5b81a2645b467a0.png

遍历:可以用 for - in 进行对象遍历。代码解释如下:

95ff75e69ce625537fa5b9e46515162d.png

修改:可以使用(.)或者([])进行修改对象的值。示例代码如下:

f64366066056a6e62fedbec44853de27.png

删除:可以通过delete关键词删除json对象属性值。示例代码如下:

42f745f0130d619aa0a55db8b5bfa758.png

完整代码截图为:

2388a2365f09deae6c5985dd3797c2d7.png

附上代码:

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"],示例代码如下:

734edbba8fd0dfcacc8ed03229ef5149.png

数组套对象:取值到对象后遵从对象的语法。示例代码如下:

9a1c080047313496eb18158f21ecd074.png

遍历:可以用 for - in 或者for 对json数组进行遍历。示例代码如下:

5515174363812e98f0ffac39efd265ef.png

修改:可以使用([])索引号进行修改数组。示例代码如下:

12ce673287ae62d717162668c456bb03.png

删除:可以通过delete关键词删除json数组中的项目。示例代码如下:

4b5d7e87da91ad12c828920645436451.png

完整json数组示例代码如下:

1dd182a03fed2cfd6ff3b04e3206399c.png

附上源码:

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串。

d8d5ecdf829896e210002ffb3c4269c5.png

在这里多说几句,你可能会对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对象这个过程就是反序列化。

ef76cb93f91b17e00522bea782f28222.png

对于json本身来说是不复杂的,但是在java中如果程序员直接操作json字符串那是一件非常麻烦和复杂的事情,不少优秀的程序员/团队/公司努力研究,将他们经验和智慧开源出来供大家使用,在其中,Gson/fastjson/Jackson要更流行一些。咱们一个个了解一下。

Gson介绍

在学习之前,你知道什么是Gson吗?
Gson是谷歌开源的一个Java库,可用于将Java对象转换为(序列化)其JSON表示形式。它还可以用于将JSON字符串转换为(反序列化)等效的Java对象。Gson可以处理任意Java对象,包括没有源代码的现有对象。下图为Gson在github主页一些信息。

6e328302c9974f0bfda8b1be161b1f54.png

每种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());

执行的结果为:

6fe0c7aa6d01b0ee89007845e7330132.png

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);

执行的结果为:

19d8d2711a4d192900f2e97984f59b11.png

我们将这些字符串复制到新的代码域进行反序列化操作,在反序列化时候,我们会用到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));

输出结果为:

15a33d7c4434a2f6828972d83b3074e1.png

上面只是介绍了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。

3820ac4b10b59c7231ca0c86cc9daabd.png

从上图可以看得出,上面这些数据结构也是根据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的主页:

ea1df421938798f6ba99b4c26b6e063c.png

学习fastjson之前同样问:什么是fastjson?

  • fastjson是阿里巴巴的开源JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean。

除了是国内阿里开源的,fastjson还有优异的性能,fastjson的优点如下:

  • 速度快:fastjson相对其他JSON库的特点是快,从2011年fastjson发布1.1.x版本之后,其性能从未被其他Java实现的JSON库超越。
  • 使用广泛、测试完备。在阿里内部有广泛的应用。
  • 使用简单、功能完备。支持泛型、复杂类型等。

34198b5fd77e99a7df6984c56fb8d422.png

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");

对应输出的结果与预期一致:

3cb45c909b9e06cec407ccc737f3a766.png

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());

控制台的输出为:

76941824fa10537502f0e6b2c0a4f5d4.png

此外,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());

得到输出结果为:

0fe139e51137f09a9f01830ccb5eb5d8.png

不难看的出,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主页情况:

618e561ba06e908dc0cb4cefcf73eddd.png

其实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());

对于上述代码执行结果为:

2abdcbccdfcc7ec17eab863d88277195.png

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());

执行结果为:

7953f821a93f87273553a4c27d1e6fe5.png

看完实例,你是不是发现:哇,原来三者有很相似的之处啊,是的,一个优秀的开源框架不光光要考虑其功能、性能,其易用性、对用户友好程度、官方文档等也是非常重要的指标!当然,这里仅仅是jackson功能的九牛一毛,更详细深入的学习需要到jackson官方文档去查阅。

Gson VS fastjson VS jackson

现在三种java的序列化/反序列化json框架都已经介绍啦。三者都是非常优秀的框架,这是毋庸置疑的,但是一对比,它就有一些伤害啊(嘤嘤嘤)。

名称GsonfastjsonJackson社区生态较好一般较好易用性易用易用一般小文件速度最快较快较慢大文件速度较慢较快较快稳定性稳定一般稳定安装包大小非常小较小一般

综上所述来说:Gson:轻便简洁,适合中小json文件的解析。在大json文件上效率略差,且其功能比较全面,生态较好。jackson:处理大文件速度快一些,且比fastjson稳定一些。生态较好。fastjson:速度较快,但经常爆出安全问题。生态一般,主要国内使用。

对选取哪个json框架主要根据自己的需要,如果是测试或者比较简单个人使用,推荐Gson和fastjson上手比较容易。如果是需要上线,那么fastjson得慎用,可能某些数据会序列化失败。

47b1c4e39b2444763984c67ff9749c0f.png

在介绍完的最后,偷偷赞扬一下咱们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团队开源的。

cf37ff256925990696b3774dd98379f7.png

轻松愉快的json介绍课程到这里就结束了,通过本节课程,你了解了json的概念,分清了json和xml的异同点,也知道了json在web领域和非关系数据库的那些应用。通过系列介绍、比较、结合实际场景相信你对json的认识肯定都是非常清晰。

紧接着文章又介绍了json的语法规则以及在java中操作json的实战操作,学习和比较了Gson、fastjson、jackson的应用以及他们之间的区别点,相信你也掌握了在java语言中json的实战能力,且能够根据自己需求灵活使用哪种框架,并深入的研究下去。

json是web技术进步与发展的产物,它是一种数据交换格式。它几乎是前后端程序员不可避免的技术点,希望大家在日后能够多多回顾课程,结合其他教材文本等,将json 从立地到成佛!加油,我们下次再会!

ecd189c23ab1dc8000504a8940676d35.png

ded7cb45b6eb071de632bdbce6b10356.png
GitHub 加速计划 / js / json
41.72 K
6.61 K
下载
适用于现代 C++ 的 JSON。
最近提交(Master分支:1 个月前 )
960b763e 4 个月前
8c391e04 6 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐