从零开始学Java之带你学习如何进行JSON解析

作者 :孙玉昌,昵称【一一哥 】,另外【壹壹哥】也是我哦

CSDN博客专家、万粉博主、阿里云专家博主、掘金优质作者

前言

在上一篇文章中,壹哥 给大家讲解了XML及其解析相关的内容,让我们了解到了XML的优缺点。实际上,因为XML文档的解析复杂性,加上对内存消耗过多,存储同样的内容,XML需要占用较多的内存和网络资源,所以目前很多项目中都已经不再使用XML了,取而代之的是JSON。今天壹哥会再利用一篇文章,来给大家讲解JSON及其解析技术,希望你能喜欢哦。

在开讲之前,壹哥 必须提醒大家,JSON解析很常用,大家必须熟练掌握!!!熟练掌握!!!熟练掌握!!!

------------------------------前戏已做完,精彩即开始----------------------------

全文大约【5700】 字,不说废话,只讲可以让你学到技术、明白原理的纯干货!本文带有丰富的案例及配图视频,让你更好地理解和运用文中的技术概念,并可以给你带来具有足够启迪的思考......

配套开源项目资料

Github: github.com/SunLtd/Lear...

Gitee: gitee.com/sunyiyi/Lea...

一. JSON简介

1. 概念

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它算是JavaScript语言的一部分,与XML一样都可以用于数据的存储和传输。一个JSON文档可以由JSON对象和JSON数组两部分组成,内部的格式由键值对组成。在实际应用中,我们经常会把JSON数组和JSON对象组合起来构建成复杂的数据结构,以满足不同的需求。

2. 优缺点

JSON这种信息载体,相比XML来说,具有自己鲜明的特点,具体来说,就是具有如下优缺点。

2.1 JSON的优点

  • 易于读写:JSON的格式非常简单,易于读写和维护;
  • 易于解析:JSON数据结构简单,解析速度快,可以很方便地被各种编程语言所解析;
  • 易于传输:JSON数据量小,传输速度快,非常适合于网络传输;
  • 易于扩展:JSON支持嵌套,可以很方便地添加新的数据结构;
  • 与JavaScript兼容:JSON是JavaScript的一个子集,可以很方便地被JavaScript解析。

2.2 JSON的缺点

但是JSON也不是说就十全十美,同样也有一些小缺点。

  • 无注释:JSON数据中不支持注释,这使得JSON文件的可读性变得较差;
  • 无标准:JSON没有统一的标准定义,各种实现之间有一定的差异;
  • 不支持二进制数据:JSON只支持文本数据,不支持二进制数据,这在一些场景中可能会受到限制;
  • 可读性差:由于JSON的格式比较简单,因此在一些复杂的数据结构中,可能会出现可读性差的情况。

但总的来说,瑕不掩瑜,JSON作为一种非常方便、易于使用的数据格式,具有良好的跨平台性和易扩展性,常用于前后端数据交互、移动应用开发、IoT应用等场景中。

3. JSON与XML对比

正是基于以上特点,所以在现代开发中,JSON比XML更常用 。毕竟JSON具有更简单、更清晰的语法和结构,同时也比XML更轻量级、更易于解析和处理。此外,JSON也更适合于Web应用程序和移动应用程序,因为它可以更快地在客户端和服务器之间传输数据。当然在某些特殊的应用场景中,如数据交换和存储等,XML仍然是一种重要的数据格式。请大家来看看壹哥做的JSON与XML对比总结,如下表所示:

**** JSON XML
格式 轻量、易读 冗长、复杂
数据类型 数组、对象、字符串、数字、布尔 数组、对象、字符串、数字、布尔
解析库 Jackson、Gson DOM、SAX、JAXB
可读性 易于阅读和理解 需要熟悉格式和标签
应用场景 前后端数据交互、API数据传输 数据存储、传输、配置

大家可以根据自己的实际需要,选择合适的格式进行数据的存储和传输。

3. 使用场景

我们现在知道,JSON作为一种轻量级的数据交换格式,具有易读性、易于编写和解析的特点,因此经常用于前后端数据交互。具体来说,经常会用于以下这些场景中:

  • Web开发中,前后端数据交互。
  • 移动应用开发中,客户端与服务器数据交互。
  • IoT应用中,设备与云端数据交互。
  • 大数据应用中,数据交换和存储。
  • 日志处理中,日志数据的存储和分析。
  • 软件测试中,数据的生成和验证。
  • 其他各种数据交换场景。

除了以上这些应用之外,当然还有很多其他的使用场景,在此壹哥就不再细说了。

二. JSON语法

1. 基本构成

JSON文档有 JSON对象和JSON数组 两种基本类型, 这两种基本类型又主要由以下几个部分组成:

  • 对象(Object) :由一组键值对组成,使用大括号({})包含,键值对之间使用逗号(,)分隔;
  • 数组(Array) :由一组有序的值组成,使用中括号([])包含,值之间使用逗号(,)分隔;
  • 值(Value) :由一组有序的值组成,使用中括号([])包含,值之间使用逗号(,)分隔;
  • 键(Key) :一个字符串,用于表示对象中的一个键值对的键;
  • 字符串(String) :由一组字符组成。在JSON中,字符串必须使用双引号("")包含;
  • 数字(Number) :一个整数或浮点数;
  • 布尔值(Boolean) :true或false;
  • 空值(Null) :表示一个空值,只有一个关键字null。

其中,JSON对象要使用 大括号{} 包裹起来 ,在大括号{}内部可以包含多个键值对。每个键值对由一个键和一个值组成,键和值之间使用冒号:分隔,而多个键值对之间要使用逗号,分隔。键值对的键是一个字符串,值可以是任意类型的数据,可以是数字、字符串、布尔值、数组或其他JSON对象。如下所示:

json 复制代码
{
    "name": "一一哥",
    "age": 25,
    "email": "yyg@example.com"
}

上面的JSON对象有三个键值对,分别是name、age和email,它们的值分别是字符串、数字和字符串类型。

JSON数组可以看作是一组有序的值,整个数组要使用 中括号[] 包裹起来 。在JSON数组中可以包裹其他的JSON对象或数组,进行多重嵌套。数组中的每个值也都可以是任意类型的数据(包括字符串、数字、对象、数组等),值之间同样使用逗号,分隔。如下所示:

json 复制代码
[
    "apple",
    "banana",
    "cherry",
    {
        "name": "一一哥",
        "age": 30
    },
    [1, 2, 3]
]

上面的JSON数组有五个值,分别是三个字符串、一个对象和一个数组。其中,第四个值是一个JSON对象,第五个值是一个JSON数组。

虽然JSON对象和JSON数组在语法上有所不同,但它们都是用来表示JSON数据的常用结构。在实际应用中,我们可以将它们组合嵌套起来构建出更加复杂的数据结构,以满足不同的需求。比如下面这个JSON文档:

json 复制代码
{
    "name": "一一哥",
    "age": 25,
    "email": "yyg@126.com",
    "hobbies": [
        "吃饭饭",
        "音乐",
        {
            "name": "钢琴",
            "level": 3
        }
    ]
}

在上面这个文档中,壹哥定义了一个包含四个键值对的JSON对象,其中name、age和email是字符串类型的key。hobbies是一个包含三个元素的JSON数组,其中前两个元素是字符串,第三个元素又是一个JSON对象,包含name和level两个键值对。注意,在JSON数组中可以包含任意类型的元素,包括字符串、数字、对象、数组等。

为了让大家更好地搞清楚JSON语法的构成,接下来壹哥再分别给大家讲解一下JSON语法中的各个组成部分。

2. 对象

JSON对象是一组由键值对组成的无序集合,用大括号{}包裹。每个键值对之间使用逗号,分隔。键是一个字符串,值可以是任意类型的数据,包括对象、数组、字符串、数字、布尔值和空值。我们来看下面这个包含了三个键值对的JSON对象:

json 复制代码
{
    "name": "一一哥",
    "age": 20,
    "city": "上海"
}

3. 数组

JSON数组是一组有序的值的集合,用中括号[]包裹。每个值之间使用逗号,分隔,值可以是任意类型的数据,包括对象、数组、字符串、数字、布尔值和空值。我们来看下面这个包含了三个值的JSON数组:

json 复制代码
["apple", "banana", "cherry"]

4. 值

JSON的值可以是任意类型的数据,包括对象、数组、字符串、数字、布尔值和空值。例如:

json 复制代码
{
    "name": "一一哥",
    "age": 20,
    "isMarried": false,
    "hobbies": ["读书", "运动", "音乐"],
    "address": {
        "street": "上海同济支路199号",
        "city": "上海",
        "zipcode": "10001"
    },
    "phoneNumbers": [
        {
            "type": "home",
            "number": "555-1234"
        },
        {
            "type": "work",
            "number": "555-5678"
        }
    ]
}

上面的JSON对象中包含了字符串、数字、布尔值、数组和对象等多种类型的值。

5. 键

JSON对象中的键必须是字符串类型,要用双引号""包裹。键应该是唯一的,重复的键会被覆盖。例如:

json 复制代码
{
    "name": "一一哥",
    "age": 30,
    "city": "上海"
}

6. 字符串

JSON字符串是由双引号""包含的任意Unicode字符序列,字符串中可以包含转义字符,如下表所示:

转义字符 描述
\" 双引号
\\ 反斜杠
\/ 正斜杠
\b 退格符
\f 换页符
\n 换行符
\r 回车符
\t 水平制表符(tab)
\uXXXX Unicode代码(XXXX表示四位数字)

例如:

json 复制代码
{
    "name": "一一哥",
    "city": "上海",
    "address": "123 Main Street\\nApt 4B"
}

7. 数字

JSON中的数字可以是整数或浮点数,可以带正负号和小数点。例如:

json 复制代码
{
    "age": 30,
    "price": 12.99,
    "temperature": -5.6
}

8. 布尔值

JSON中的布尔值只有两个取值,即true和false。例如:

json 复制代码
{
    "isMarried": true,
    "hasChildren": false
}

9. 空值

JSON中的空值表示为null。例如:

json 复制代码
{
    "name": "一一哥",
    "address": null
}

在JSON解析时,我们可以将null转换为Java中的null值,表示缺少数据。

熟悉了JSON的基本语法之后,壹哥再来带大家学习如何实现JSON解析,该部分的内容主要包括将一个Java对象转为JSON字符串,和把JSON字符串转为对应的Java对象。

三. JSON解析

1. 概述

我们先来看看什么是JSON解析。

JSON解析就是把使用JSON格式编写的数据,转换为计算机程序可以使用的数据类型。在Java中,有许多JSON解析库可供我们进行使用,比如Jackson、FastJSON、Gso n 等。接下来壹哥主要是结合Java推荐的Jackson来给大家介绍JSON解析的概念、原理和具体实现方法。

2. JSON解析原理

在我们开始进行JSON解析之前,我们先来看看解析的实现原理。

JSON解析的实现原理其实就是将JSON字符串转换为Java对象,或反过来将Java对象转换为JSON字符串 。其中,将Java对象转换为JSON字符串的过程称为序列化;反之,将JSON字符串转换为Java对象的过程称为反序列化 。在Java中,我们通常是使用反射技术来实现JSON解析,即根据JSON字符串中的数据类型,利用Java的反射机制动态地创建出对应的Java对象,并将JSON字符串中的数据赋值给Java对象的各个属性。

3. Jackson简介

3.1 概述

Jackson是一个流行的Java JSON解析库,可以将JSON字符串转换为Java对象,也可以将Java对象转换为JSON字符串 。它支持流式API、数据绑定和树模型等多种解析方式,同时还给我们提供了许多注解,用于控制JSON序列化和反序列化。具有性能高、使用简单等优点。

3.2 常用API

我们在利用Jackson开发时,肯定会用到ObjectMapper类,该类是Jackson框架中最核心的类之一,它可以将Java对象转换为JSON字符串,或反过来将JSON字符串转换为Java对象。以下是ObjectMapper类的一些常用方法:

  • readValue:将JSON字符串转换为Java对象;
  • writeValueAsString:将Java对象转换为JSON字符串;
  • writeValue:将Java对象写入输出流中。

这几个方法需要大家牢牢记住,除此之外,Jackson中还有以下几个常用的注解:

  • @JsonProperty:用于在JSON属性名和Java属性名之间建立起映射关系;
  • @JsonFormat:用于指定日期类型的格式;
  • @JsonIgnore:用于指定某个属性,不参与序列化和反序列化;
  • @JsonInclude:用于指定某个属性的条件序列化和反序列化。

3.3 核心依赖

由于Jackson并不是Java本身自带的API,所以如果我们想在Java中使用Jackson,就需要导入相关的依赖。如果我们是在Maven项目中,可以通过如下坐标导入依赖:

xml 复制代码
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.12.3</version>
</dependency>

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.3</version>
</dependency>

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.12.3</version>
</dependency>

其中,jackson-core和jackson-databind是Jackson最常用的模块,里面包含了JSON序列化和反序列化的核心功能。我们还可以根据需要导入其他的Jackson模块,如jackson-annotations等。因为我们现在还没有学习Maven,所以只能手动导入相关的依赖了。在导入依赖之后,我们就可以开始使用Jackson进行JSON解析了,请大家继续往下看。

3. 序列化

我们在进行前后端数据交互时,前端通常是使用JSON格式来传递数据,后端则需要将这些JSON格式的数据转换为Java对象进行处理。同时,后端也需要将Java对象转换为JSON格式,以便前端使用。所以前后端之间就需要进行不同格式之间的转换,这就是序列化和反序列化。壹哥 在前面讲过,序列化就是将Java对象转换为JSON字符串的过程

3.1 对象转字符串

我们先来看一个简单的序列化代码,将一个Java对象转为json字符串,如下所示:

java 复制代码
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * @author 一一哥Sun
 */
public class Demo01 {
    public static void main(String[] args) {
        try {
            //创建一个Person对象
            Person person=new Person();
            person.setName("一一哥");
            person.setAge(20);
            person.setAddress("上海校区");
			
            //创建一个ObjectMapper对象映射对象
            ObjectMapper mapper = new ObjectMapper();
            //序列化:将Java对象转为json字符串
            String json = mapper.writeValueAsString(person);
            System.out.println("json="+json);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }
}

执行结果如下图所示:

3.2 集合转字符串

除了可以将单个Java对象转为JSON字符串之外,我们还可以将Java数组、集合等复杂对象类型转为JSON字符串,实现Java对象与JSON数组之间的转换。代码如下所示:

java 复制代码
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * @author 一一哥Sun
 */
public class Demo03 {
    public static void main(String[] args) {
        try {
             //创建一个集合
             Map<String,List<Person>> map=new HashMap<>();
             List<Person> list=new ArrayList<>();
			
             Person p1=new Person();
             p1.setName("一一哥");
             p1.setAge(20);
             p1.setAddress("山东");
			
             Person p2=new Person();
             p2.setName("壹哥");
             p2.setAge(18);
             p2.setAddress("北京校区");
			
             Person p3=new Person();
             p3.setName("孙老师");
             p3.setAge(30);
             p3.setAddress("青岛校区");
			
             list.add(p1);
             list.add(p2);
             list.add(p3);
			
             map.put("persons", list);
			
             //创建一个ObjectMapper对象映射对象
             ObjectMapper mapper = new ObjectMapper();
             //序列化:将Java对象转为json字符串
             String json = mapper.writeValueAsString(map);
             System.out.println("json="+json);
         } catch (JsonProcessingException e) {
             e.printStackTrace();
         }
    }
}

执行结果如下图所示:

4. 反序列化

4.1 字符串转对象

而反序列化,就是将JSON字符串转换为Java对象的过程。我们来看看如下代码:

java 复制代码
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * @author 一一哥Sun
 */
public class Demo02 {
    public static void main(String[] args) {
        //先创建一个ObjectMapper对象映射对象
        ObjectMapper mapper = new ObjectMapper();
        //允许json字符串中有单引号,解决JsonParseException: 
        //Unexpected character (''' (code 39)): was expecting double-quote to start field name
        mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); 
        String jsonString = "{'name':'一一哥','age':18,'address':'上海'}";
        try {
            //反序列化:将JSON字符串转换为对应的Java对象
            Person person = mapper.readValue(jsonString, Person.class);
            System.out.println(person.getName()+"--"+person.getAge()+"--"+person.getAddress());
        } catch (JsonProcessingException e) {
            //处理json处理异常
            e.printStackTrace();
        }
    }
}

执行结果如下图所示:

在上面的案例中,我们首先创建了一个ObjectMapper对象,然后使用readValue方法将JSON字符串转换为Person对象。Person类需要拥有对应的属性和getter/setter方法,最后输出了person对象的name和age等属性。

4.2 字符串转集合

除了可以将JSON字符串转为单个对象,我们也可以将一个复杂的JSON字符串转为一个合适的集合对象类型。

java 复制代码
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * @author 一一哥Sun
 */
public class Demo04 {
    public static void main(String[] args) {
        // 先创建一个ObjectMapper对象映射对象
        ObjectMapper mapper = new ObjectMapper();
        // 允许json字符串中有单引号,解决JsonParseException:
        // Unexpected character (''' (code 39)): was expecting double-quote to start
        // field name
        mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        String jsonString = "{'persons':[{'name':'一一哥','age':20,'address':'上海校区'},{'name':'壹哥','age':18,'address':'北京校区'}]}";
        try {
            // 反序列化:将JSON字符串转换为对应的Java对象
            //直接将json字符串转为对应的Java对象
            Persons persons = mapper.readValue(jsonString, Persons.class);
            List<Person> list = persons.getPersons();
            for (Person person : list) {
                System.out.println(person.getName() + "--" + person.getAge() + "--" + person.getAddress());
            }

            // 也可以直接将json字符串转为Map集合
            Map<String, Person> map = mapper.readValue(jsonString, Map.class);
            for (Map.Entry<String, Person> entry : map.entrySet()) {
                System.out.println(entry.toString());
            }
        } catch (JsonProcessingException e) {
             // 处理json处理异常
             e.printStackTrace();
        }
    }
}

执行结果如下图所示:

在上面的案例中,我们创建了一个Persons类,内部包含了一个包含Person对象的List列表。然后使用ObjectMapper对象将JSON字符串转换为Person对象,最后遍历PersonList中的每个Person对象,输出其属性值。这个案例中,JSON字符串中的name、age和address属性,分别对应了Person类中的name、age和address属性。

我们就是通过以上这几种方式,实现了Java对象与JSON字符串之间的转换,你学会了吗?

5. 注意事项

我们在进行JSON解析时,需要注意以下几个问题:

  • JSON字符串必须是有效的JSON格式,否则会导致解析失败
  • Java类中的属性的名称和类型,必须与JSON对象或JSON数组中的键和值相对应;
  • JSON字符串中的键必须是字符串类型,用双引号包裹;
  • Java类中的属性类型必须与JSON字符串中的值类型相对应;
  • 使用Jackson进行JSON解析时,需要将JSON字符串的Unicode转义符进行转义,例如将"\"转换为"\\";
  • JSON字符串中的键必须是唯一的,重复的键会被覆盖;
  • JSON字符串中的数组必须使用中括号包裹,并使用逗号分隔数组元素。

以上这些注意事项,大家一定要认真对待,否则可能会导致你出现一些莫名其妙的错误哦。

------------------------------正片已结束,来根事后烟----------------------------

四. 结语

壹哥 在本文给大家详细介绍了JSON解析的概念、原理和使用方法,并以Jackson为例进行了详细的实现。壹哥希望大家熟练掌握JSON解析,因为这个技术实在是太常用了哦。在实际开发中,我们要根据实际需求选择合适的JSON解析方式,并根据具体的情况选择相应的注解,以便让JSON解析更加得便捷和高效。

另外如果你独自学习觉得有很多困难,可以加入壹哥的学习互助群,大家一起交流学习。

相关推荐
啊松同学20 分钟前
【Java】设计模式——工厂模式
java·后端·设计模式
枫叶_v1 小时前
【SpringBoot】20 同步调用、异步调用、异步回调
java·spring boot·后端
鸣弦artha1 小时前
蓝桥杯——杨辉三角
java·算法·蓝桥杯·eclipse
大波V51 小时前
设计模式-参考的雷丰阳老师直播课
java·开发语言·设计模式
计算机-秋大田1 小时前
基于微信小程序的平安驾校预约平台的设计与实现(源码+LW++远程调试+代码讲解等)
java·spring boot·微信小程序·小程序·vue·课程设计
《源码好优多》1 小时前
基于Java Springboot旅游信息推荐系统
java·spring boot·旅游
岁月无声code1 小时前
Spring Boot 牛刀小试 org.springframework.boot:spring-boot-maven-plugin:找不到类错误
java·spring boot·github
不爱学习的YY酱2 小时前
【计网不挂科】计算机网络第二章< 物理层 >习题库(含答案)
java·数据库·计算机网络
南城花随雪。2 小时前
Spring框架之装饰者模式 (Decorator Pattern)
java·开发语言·装饰器模式
编程、小哥哥2 小时前
设计模式之装饰器模式(SSO单点登录功能扩展,增加拦截用户访问方法范围场景)
java·设计模式·装饰器模式