【学习】JSON语言详解与Java应用实践
前言
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。它基于JavaScript编程语言的一个子集,但独立于语言,几乎所有的现代编程语言都有解析和生成JSON的库。由于其简洁性和易用性,JSON已成为Web应用、API接口、配置文件等领域首选的数据格式之一。本文将详细介绍JSON的语法、特性、常见应用场景,并重点阐述如何在Java应用中使用流行的库(如Jackson和Gson)处理JSON数据。
一、什么是JSON?
JSON由道格拉斯·克罗克福特(Douglas Crockford)在2001年构思和推广,旨在替代XML作为一种更轻量的数据交换格式。它的设计目标是最小化复杂性,使其尽可能地简单和通用。
(一)核心特点
- 轻量级:相比XML等其他数据格式,JSON的语法更简洁,冗余更少,因此文件体积通常更小,传输效率更高。
- 易读性强:JSON的结构清晰,键值对的表达方式直观,非常接近人类自然语言的表达习惯。
- 易于解析和生成:对于计算机而言,JSON的结构化数据很容易被解析成编程语言中的数据结构(如对象或字典、数组或列表),反之亦然。
- 语言独立:虽然源于JavaScript,但JSON是一种通用的数据格式,几乎所有主流编程语言都有成熟的库支持JSON操作。
- 基于文本:JSON完全由文本构成,方便在不同系统间传输和存储。
(二)文件扩展名
JSON文件通常使用 .json
作为扩展名。
(三)基本语法规则
JSON的语法基于两种结构:
- 对象(Object):一个无序的”名称/值”对集合(也称为键值对、字典、哈希表)。
- 对象以花括号
{}
包围。 - 每个名称/值对之间用逗号
,
分隔。 - 名称和值之间用冒号
:
分隔。 - 名称(键)必须是字符串,并且用双引号
"
包围。
- 对象以花括号
- 数组(Array):值的有序列表。
- 数组以方括号
[]
包围。 - 数组中的值之间用逗号
,
分隔。
- 数组以方括号
二、JSON数据类型
JSON支持以下几种基本数据类型作为值:
(一)对象(Object)
对象是一系列键值对的集合,其中键是字符串,值可以是任何合法的JSON数据类型。
1 | { |
(二)数组(Array)
数组是值的有序集合,值可以是任何合法的JSON数据类型。
1 | { |
(三)值(Value)
JSON的值可以是以下几种类型:
字符串(String)
- 由双引号
"
包围的Unicode字符序列。 - 支持反斜杠
\
转义特殊字符,如\"
(双引号),\\
(反斜杠),\b
(退格),\f
(换页),\n
(换行),\r
(回车),\t
(制表符), 以及\uXXXX
(四位十六进制Unicode字符)。1
"message": "Hello, \"World\"!\nThis is a new line."
- 由双引号
数字(Number)
- 可以是整数或浮点数。
- 不支持八进制和十六进制表示法。
- 不支持
NaN
(Not a Number) 或Infinity
。1
2
3"count": 100,
"price": 19.99,
"scientific": 6.022e23
布尔值(Boolean)
true
或false
(小写)。1
2"isActive": true,
"isComplete": false
null
- 表示空值或无值,使用小写
null
。1
"middleName": null
- 表示空值或无值,使用小写
三、JSON与其他数据格式的比较
(一)与XML比较
特性 | JSON | XML (Extensible Markup Language) |
---|---|---|
语法 | 键值对,数组 | 标签,属性,文本内容 |
可读性 | 通常更简洁,易读 | 结构清晰,但标签冗余较多 |
解析速度 | 通常更快 | 相对较慢 |
文件大小 | 通常更小 | 通常较大,因标签开销 |
数据类型 | 字符串, 数字, 布尔, 数组, 对象, null | 主要基于文本,类型通过DTD/Schema定义 |
注释 | 不支持 (标准JSON规范中无注释) | 支持 (<!-- comment --> ) |
命名空间 | 不支持 | 支持 |
扩展性 | 简单直接 | 高度可扩展 (通过DTD/Schema) |
浏览器支持 | 内建支持 (JavaScript原生解析) | 需要DOM解析器 |
JSON通常在Web API和轻量级数据交换中由于其简洁性而优于XML。XML在需要复杂结构、元数据、验证(通过Schema)和文档标记的场景中仍有其优势。
(二)与YAML比较
特性 | JSON | YAML (YAML Ain't Markup Language) |
---|---|---|
可读性 | 较高,但括号和引号较多 | 非常高,使用缩进和简洁符号 |
注释 | 不支持 | 支持 (# ) |
数据类型 | 基本 (字符串, 数字, 布尔, null, 数组, 对象) | 丰富 (额外支持日期, 时间戳等,更灵活的标量) |
复杂结构 | 无内置支持 (如锚点和别名) | 支持锚点&别名, 合并键, 多行字符串 |
严格性 | 严格 (键和字符串必须用双引号) | 相对宽松 (例如字符串通常不需引号) |
超集关系 | 是YAML的子集 | 是JSON的超集 (大部分合法JSON也是合法YAML) |
YAML在配置文件(如Docker Compose, Kubernetes)中因其出色的可读性和支持注释、锚点等高级特性而非常流行。JSON更侧重于作为纯粹的数据交换格式。
四、JSON的常见应用场景
- Web API:绝大多数现代Web API(RESTful API, GraphQL API等)使用JSON作为请求和响应的数据格式。
- 配置文件:许多应用程序和服务使用JSON文件来存储配置信息(如
package.json
in Node.js, Visual Studio Code settings)。 - 数据存储:NoSQL数据库(如MongoDB, CouchDB)经常使用JSON或类JSON的文档格式(如BSON)来存储数据。
- 日志记录:结构化日志常采用JSON格式,便于机器解析和分析。
- 客户端-服务器通信:Web应用和移动应用与后端服务器之间的数据交换。
- 消息队列:在分布式系统中,消息队列中的消息内容也常使用JSON格式。
五、在Java应用中使用JSON
Java生态系统中有许多优秀的库可以方便地处理JSON的序列化(Java对象转换为JSON字符串)和反序列化(JSON字符串转换为Java对象)。其中最流行的两个是Jackson和Gson。
(一)选择Java JSON库
- Jackson:功能非常强大且全面的库,性能优秀,提供了丰富的功能和注解来控制序列化和反序列化过程。Spring框架默认使用Jackson。
- Gson:由Google开发,易于使用,对POJO的序列化和反序列化非常方便,对处理没有对应Java类的任意JSON结构也提供了良好的支持。
两者都是优秀的选择,具体选择哪个取决于项目需求、团队熟悉度和特定功能偏好。
(二)使用Jackson库
Jackson是Java中使用最广泛的JSON处理库之一。
1. 添加依赖
Maven:
1 | <dependency> |
Gradle:
1 | implementation 'com.fasterxml.jackson.core:jackson-databind:2.16.0' // 请检查并使用最新版本 |
2. POJO示例
假设我们有以下Java类:
1 | // Person.java |
3. 解析JSON到Java对象(反序列化)
1 | import com.fasterxml.jackson.databind.ObjectMapper; |
4. 序列化Java对象到JSON
1 | import com.fasterxml.jackson.databind.ObjectMapper; |
(三)使用Gson库
Gson是Google提供的另一个强大的Java JSON库。
1. 添加依赖
Maven:
1 | <dependency> |
Gradle:
1 | implementation 'com.google.code.gson:gson:2.10.1' // 请检查并使用最新版本 |
2. 解析JSON到Java对象(反序列化)
使用与Jackson示例相同的 Person.java
和 Address.java
POJO。Gson通常不需要显式的默认构造函数,但拥有它们是好习惯。
1 | import com.google.gson.Gson; |
3. 序列化Java对象到JSON
1 | import com.google.gson.Gson; |
六、编写JSON的最佳实践与注意事项
- 键名规范:建议使用驼峰命名法(
camelCase
)或下划线命名法(snake_case
)并保持一致性。 - 字符串使用双引号:JSON规范要求字符串和键名都必须使用双引号。单引号或无引号的字符串是不合法的。
- 避免尾随逗号:对象或数组的最后一个元素后面不应有逗号,这在某些解析器中会导致错误(尽管一些现代解析器可能更宽容)。
1
2
3
4// 错误示例
{ "key": "value", }
// 正确示例
{ "key": "value" } - 数据类型正确性:确保数字就是数字(不要用引号包围),布尔值就是
true
/false
。 - UTF-8编码:推荐使用UTF-8编码处理JSON数据,以支持广泛的字符集。
- 安全性:
- 当从不可信来源接收JSON数据并将其反序列化为Java对象时,要注意潜在的安全风险,如”反序列化漏洞”。使用最新版本的库,并谨慎处理复杂对象图。
- 避免直接将用户输入的JSON字符串注入到JavaScript
eval()
中,这会导致XSS(跨站脚本)漏洞。
- 大小写敏感:JSON中的键名是大小写敏感的 (
"Name"
和"name"
是不同的键)。 - 不含注释:标准JSON格式不支持注释。如果需要在JSON文件中添加注释,通常的做法是添加一个描述性的键(如
"_comment": "This is a comment"
),或者使用支持注释的超集格式如JSONC (JSON with Comments) 或YAML。 - 保持简洁:尽量避免不必要的嵌套层级,使JSON结构尽可能扁平化和易于理解。
七、总结
JSON以其简洁、易读、易于机器处理的特性,已经成为现代软件开发中不可或缺的数据交换格式。无论是在Web API、配置文件还是各种应用程序的内部数据通信中,JSON都扮演着核心角色。在Java开发中,借助Jackson、Gson等强大的库,开发者可以非常便捷地实现Java对象与JSON数据之间的转换,极大地提高了开发效率。理解JSON的语法规范和最佳实践,有助于构建更健壮、更高效的应用程序。
八、参考资料
- JSON官方网站: https://www.json.org/
- ECMA-404 The JSON Data Interchange Standard: https://www.ecma-international.org/publications-and-standards/standards/ecma-404/
- MDN Web Docs - JSON: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON
- Jackson Databind GitHub: https://github.com/FasterXML/jackson-databind
- Gson GitHub: https://github.com/google/gson
- Baeldung - Introduction to Jackson: https://www.baeldung.com/jackson-object-mapper-tutorial
- Baeldung - Gson Tutorial: https://www.baeldung.com/gson-list (虽然标题是list,但内容全面)