Java学习之如何进行JSON解析
作者:一一哥Sun
一. 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数据传输 | 数据存储、传输、配置 |
大家可以根据自己的实际需要,选择合适的格式进行数据的存储和传输。
4. 使用场景
我们现在知道,JSON作为一种轻量级的数据交换格式,具有易读性、易于编写和解析的特点,因此经常用于前后端数据交互。具体来说,经常会用于以下这些场景中:
- Web开发中,前后端数据交互。
- 移动应用开发中,客户端与服务器数据交互。
- IoT应用中,设备与云端数据交互。
- 大数据应用中,数据交换和存储。
- 日志处理中,日志数据的存储和分析。
- 软件测试中,数据的生成和验证。
- 其他各种数据交换场景。
除了以上这些应用之外,当然还有很多其他的使用场景,在此就不再细说了。
二. JSON语法
1. 基本构成
JSON文档有 JSON对象和JSON数组 两种基本类型, 这两种基本类型又主要由以下几个部分组成:
- 对象(Object) :由一组键值对组成,使用大括号({})包含,键值对之间使用逗号(,)分隔;
- 数组(Array) :由一组有序的值组成,使用中括号([])包含,值之间使用逗号(,)分隔;
- 值(Value) :由一组有序的值组成,使用中括号([])包含,值之间使用逗号(,)分隔;
- 键(Key) :一个字符串,用于表示对象中的一个键值对的键;
- 字符串(String) :由一组字符组成。在JSON中,字符串必须使用双引号("")包含;
- 数字(Number) :一个整数或浮点数;
- 布尔值(Boolean) :true或false;
- 空值(Null) :表示一个空值,只有一个关键字null。
其中,JSON对象要使用大括号{}
包裹起来,在大括号{}内部可以包含多个键值对。每个键值对由一个键和一个值组成,键和值之间使用冒号:
分隔,而多个键值对之间要使用逗号,
分隔。键值对的键是一个字符串,值可以是任意类型的数据,可以是数字、字符串、布尔值、数组或其他JSON对象。如下所示:
{ "name": "一一哥", "age": 25, "email": "yyg@example.com" }
上面的JSON对象有三个键值对,分别是name、age和email,它们的值分别是字符串、数字和字符串类型。
而JSON数组可以看作是一组有序的值,整个数组要使用中括号[]
包裹起来。在JSON数组中可以包裹其他的JSON对象或数组,进行多重嵌套。数组中的每个值也都可以是任意类型的数据(包括字符串、数字、对象、数组等),值之间同样使用逗号,
分隔。如下所示:
[ "apple", "banana", "cherry", { "name": "一一哥", "age": 30 }, [1, 2, 3] ]
上面的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对象:
{ "name": "一一哥", "age": 20, "city": "上海" }
3. 数组
JSON数组是一组有序的值的集合,用中括号[]
包裹。每个值之间使用逗号,
分隔,值可以是任意类型的数据,包括对象、数组、字符串、数字、布尔值和空值。我们来看下面这个包含了三个值的JSON数组:
["apple", "banana", "cherry"]
4. 值
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对象中的键必须是字符串类型,要用双引号""
包裹。键应该是唯一的,重复的键会被覆盖。例如:
{ "name": "一一哥", "age": 30, "city": "上海" }
6. 字符串
JSON字符串是由双引号""
包含的任意Unicode字符序列,字符串中可以包含转义字符,如下表所示:
转义字符 | 描述 |
---|---|
\" | 双引号 |
\\ | 反斜杠 |
\/ | 正斜杠 |
\b | 退格符 |
\f | 换页符 |
\n | 换行符 |
\r | 回车符 |
\t | 水平制表符(tab) |
\uXXXX | Unicode代码(XXXX表示四位数字) |
例如:
{ "name": "一一哥", "city": "上海", "address": "123 Main Street\\nApt 4B" }
7. 数字
JSON中的数字可以是整数或浮点数,可以带正负号和小数点。例如:
{ "age": 30, "price": 12.99, "temperature": -5.6 }
8. 布尔值
JSON中的布尔值只有两个取值,即true和false。例如:
{ "isMarried": true, "hasChildren": false }
9. 空值
JSON中的空值表示为null。例如:
{ "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项目中,可以通过如下坐标导入依赖:
<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解析了,请大家继续往下看。
4. 序列化
我们在进行前后端数据交互时,前端通常是使用JSON格式来传递数据,后端则需要将这些JSON格式的数据转换为Java对象进行处理。同时,后端也需要将Java对象转换为JSON格式,以便前端使用。所以前后端之间就需要进行不同格式之间的转换,这就是序列化和反序列化。在前面讲过,序列化就是将Java对象转换为JSON字符串的过程 。
4.1 对象转字符串
我们先来看一个简单的序列化代码,将一个Java对象转为json字符串,如下所示:
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(); } } }
执行结果如下图所示:
4.2 集合转字符串
除了可以将单个Java对象转为JSON字符串之外,我们还可以将Java数组、集合等复杂对象类型转为JSON字符串,实现Java对象与JSON数组之间的转换。代码如下所示:
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(); } } }
执行结果如下图所示:
5. 反序列化
5.1 字符串转对象
而反序列化,就是将JSON字符串转换为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等属性。
5.2 字符串转集合
除了可以将JSON字符串转为单个对象,我们也可以将一个复杂的JSON字符串转为一个合适的集合对象类型。
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字符串之间的转换,你学会了吗?
6. 注意事项
我们在进行JSON解析时,需要注意以下几个问题:
- JSON字符串必须是有效的JSON格式,否则会导致解析失败;
- Java类中的属性的名称和类型,必须与JSON对象或JSON数组中的键和值相对应;
- JSON字符串中的键必须是字符串类型,用双引号包裹;
- Java类中的属性类型必须与JSON字符串中的值类型相对应;
- 使用Jackson进行JSON解析时,需要将JSON字符串的Unicode转义符进行转义,例如将"\"转换为"\\";
- JSON字符串中的键必须是唯一的,重复的键会被覆盖;
- JSON字符串中的数组必须使用中括号包裹,并使用逗号分隔数组元素。
以上这些注意事项,大家一定要认真对待,否则可能会导致你出现一些莫名其妙的错误哦。
四. 结语
在本文给大家详细介绍了JSON解析的概念、原理和使用方法,并以Jackson为例进行了详细的实现。希望大家熟练掌握JSON解析,因为这个技术实在是太常用了哦。在实际开发中,我们要根据实际需求选择合适的JSON解析方式,并根据具体的情况选择相应的注解,以便让JSON解析更加得便捷和高效。
以上就是详解如何使用Java进行JSON解析的详细内容,更多关于Java进行JSON解析的资料请关注脚本之家其它相关文章!