JSON 字符串的基本格式
要明确一点:JSON 字符串 本质上是一个用单引号或双引号包裹的、符合 JSON 规范的 普通 Java 字符串。

它的格式完全遵循 JSON (JavaScript Object Notation) 的标准,核心是键值对的集合。
基本结构
-
对象: 使用花括号 表示,是一个无序的“键/值”对集合。
- 键必须是字符串(必须用双引号 包裹)。
- 值可以是字符串、数字、布尔值、数组、对象,甚至是
null。 - 键值对之间用逗号 分隔。
-
数组: 使用方括号
[]表示,是一个有序的值列表。- 数组中的值可以是字符串、数字、布尔值、数组、对象,甚至是
null。 - 值之间用逗号 分隔。
- 数组中的值可以是字符串、数字、布尔值、数组、对象,甚至是
数据类型示例
一个典型的 JSON 字符串可能包含以下几种数据类型:

{
"name": "张三",
"age": 30,
"isStudent": false,
"address": {
"city": "北京",
"street": "中关村大街1号"
},
"courses": [
"Java编程",
"数据库原理",
"计算机网络"
],
"phone": null
}
在 Java 中的表现形式
在 Java 代码中,这个 JSON 结构会被表示为一个 String 类型,为了可读性,通常会进行格式化(缩进和换行)。
String jsonString = "{\n" +
" \"name\": \"张三\",\n" +
" \"age\": 30,\n" +
" \"isStudent\": false,\n" +
" \"address\": {\n" +
" \"city\": \"北京\",\n" +
" \"street\": \"中关村大街1号\"\n" +
" },\n" +
" \"courses\": [\n" +
" \"Java编程\",\n" +
" \"数据库原理\",\n" +
" \"计算机网络\"\n" +
" ],\n" +
" \"phone\": null\n" +
"}";
关键点:
- 整个 JSON 结构是一个字符串,所以最外层用双引号 包裹。
- JSON 内部的字符串(如
"张三")也必须用双引号 包裹。 - 在 Java 字符串中,双引号 是一个特殊字符,需要用反斜杠
\进行转义,即\"。 - JSON 中没有
char、long、Date等类型,它们会被表示为字符串、数字或特定格式的字符串。
如何在 Java 中处理 JSON 字符串
手动拼接 JSON 字符串非常繁琐且容易出错,在实际开发中,我们通常使用成熟的 JSON 库来完成 Java 对象与 JSON 字符串之间的转换。
最主流的三个库是:
- Jackson: 性能最好,功能最强大,是 Spring Boot 的默认选择。
- Gson: Google 出品,API 简洁易用,对复杂类型的处理非常友好。
- Fastjson: 阿里巴巴出品,解析速度极快,但在早期版本中存在一些安全漏洞,新版本已修复。
下面我们分别介绍这三个库的使用方法。
示例 Java 对象
为了演示,我们先创建一个与上面 JSON 结构对应的 Java 类(POJO)。
// Address.java
public class Address {
private String city;
private String street;
// Getters, Setters, toString() 等方法...
// 为了简洁,这里省略,实际开发中必须添加
}
// Student.java
public class Student {
private String name;
private int age;
private boolean isStudent;
private Address address;
private List<String> courses;
private String phone;
// Getters, Setters, toString() 等方法...
// 为了简洁,这里省略,实际开发中必须添加
}
1 使用 Jackson
添加 Maven 依赖:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version> <!-- 使用最新稳定版本 -->
</dependency>
将 Java 对象 转换为 JSON 字符串 (序列化)
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonExample {
public static void main(String[] args) {
// 1. 创建 ObjectMapper 实例
ObjectMapper objectMapper = new ObjectMapper();
// 2. 创建 Java 对象
Address address = new Address();
address.setCity("北京");
address.setStreet("中关村大街1号");
Student student = new Student();
student.setName("张三");
student.setAge(30);
student.setStudent(false);
student.setAddress(address);
student.setCourses(Arrays.asList("Java编程", "数据库原理", "计算机网络"));
student.setPhone(null);
try {
// 3. 将对象转换为 JSON 字符串
// objectMapper.writeValueAsString() 会将对象序列化为紧凑格式的 JSON 字符串
String jsonString = objectMapper.writeValueAsString(student);
System.out.println("紧凑格式:");
System.out.println(jsonString);
// 4. 格式化输出 (美化 JSON)
// 使用 writerWithDefaultPrettyPrinter() 可以生成格式化的、易读的 JSON
String prettyJsonString = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(student);
System.out.println("\n格式化输出:");
System.out.println(prettyJsonString);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
}
将 JSON 字符串 转换为 Java 对象 (反序列化)
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonExample {
public static void main(String[] args) {
String jsonString = "{\"name\":\"张三\",\"age\":30,\"isStudent\":false,\"address\":{\"city\":\"北京\",\"street\":\"中关村大街1号\"},\"courses\":[\"Java编程\",\"数据库原理\",\"计算机网络\"],\"phone\":null}";
ObjectMapper objectMapper = new ObjectMapper();
try {
// 将 JSON 字符串转换为 Student 对象
Student student = objectMapper.readValue(jsonString, Student.class);
System.out.println(student);
System.out.println("学生姓名: " + student.getName());
System.out.println("所在城市: " + student.getAddress().getCity());
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
}
2 使用 Gson
添加 Maven 依赖:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version> <!-- 使用最新稳定版本 -->
</dependency>
将 Java 对象 转换为 JSON 字符串 (序列化)
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class GsonExample {
public static void main(String[] args) {
// 1. 创建 Gson 实例
// 默认是紧凑格式
Gson gson = new Gson();
// 创建一个可以格式化输出的 Gson 实例
Gson prettyGson = new GsonBuilder().setPrettyPrinting().create();
// 2. 创建 Java 对象 (同上)
Address address = new Address();
address.setCity("北京");
address.setStreet("中关村大街1号");
Student student = new Student();
student.setName("张三");
student.setAge(30);
student.setStudent(false);
student.setAddress(address);
student.setCourses(Arrays.asList("Java编程", "数据库原理", "计算机网络"));
student.setPhone(null);
// 3. 将对象转换为 JSON 字符串
String jsonString = gson.toJson(student);
System.out.println("紧凑格式:");
System.out.println(jsonString);
String prettyJsonString = prettyGson.toJson(student);
System.out.println("\n格式化输出:");
System.out.println(prettyJsonString);
}
}
将 JSON 字符串 转换为 Java 对象 (反序列化)
import com.google.gson.Gson;
public class GsonExample {
public static void main(String[] args) {
String jsonString = "{\"name\":\"张三\",\"age\":30,\"isStudent\":false,\"address\":{\"city\":\"北京\",\"street\":\"中关村大街1号\"},\"courses\":[\"Java编程\",\"数据库原理\",\"计算机网络\"],\"phone\":null}";
Gson gson = new Gson();
// 将 JSON 字符串转换为 Student 对象
Student student = gson.fromJson(jsonString, Student.class);
System.out.println(student);
System.out.println("学生姓名: " + student.getName());
System.out.println("所在城市: " + student.getAddress().getCity());
}
}
最佳实践和注意事项
-
永远不要手动拼接 JSON
- 可读性差:代码像一团乱麻。
- 易出错:忘记转义引号、逗号,导致 JSON 格式错误。
- 维护困难:增删字段时修改成本高。
- 正确做法:定义好 Java 实体类,使用 Jackson/Gson 等库进行序列化和反序列化。
-
处理日期和时间
- JSON 本身没有日期类型,默认情况下,Jackson/Gson 会将日期序列化为时间戳(如
1678886400000)或 ISO-8601 格式的字符串(如"2025-03-15T10:00:00Z")。 - 如果需要自定义格式,可以使用注解:
- Jackson:
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") - Gson:
@SerializedName("create_time")和自定义TypeAdapter。
- Jackson:
- JSON 本身没有日期类型,默认情况下,Jackson/Gson 会将日期序列化为时间戳(如
-
处理循环引用
- 如果两个对象相互引用(如
A包含B,B又包含A),在序列化时会无限递归,最终导致StackOverflowError。 - 解决方案:
- Jackson: 使用
@JsonIgnore注解在其中一个引用上,或者使用@JsonManagedReference和@JsonBackReference。 - Gson: 使用
ExclusionStrategy或自定义TypeAdapter来处理。
- Jackson: 使用
- 如果两个对象相互引用(如
-
处理
null值- 默认情况下,序列化时会包含
null字段(如"phone": null)。 - 如果希望省略
null字段,可以这样配置:- Jackson:
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - Gson:
new GsonBuilder().serializeNulls().create();(默认包含,excludeFieldsWithModifiers()可以排除)
- Jackson:
- 默认情况下,序列化时会包含
-
安全性
- JSON 数据来源于不可信的用户(如网络请求),要警惕 反序列化攻击,攻击者可能会构造恶意的 JSON 数据,导致服务器在反序列化时执行任意代码。
- 解决方案:
- Jackson: 使用
ObjectMapper.enableDefaultTyping()或@JsonTypeInfo等功能时要非常小心,它们可能带来风险,最佳实践是禁用默认类型,只反序列化已知的、可信的类型。 - Fastjson: 旧版有严重漏洞,建议升级到最新版本并遵循其安全配置指南。
- 通用做法: 对输入数据进行严格的校验和过滤。
- Jackson: 使用
| 特性 | 手动拼接 | Jackson | Gson |
|---|---|---|---|
| 易用性 | 极差 | 高 | 高 |
| 性能 | - | 优秀 | 良好 |
| 功能 | - | 非常强大 | 功能齐全 |
| 集成度 | - | Spring Boot 默认 | 需要手动集成 |
| 推荐场景 | 不推荐 | 企业级应用、Spring Boot 项目首选 | 简单项目、Google 生态项目 |
对于任何严肃的 Java 项目,强烈推荐使用 Jackson 或 Gson 这样的专业库来处理 JSON,这能让你从繁琐且易错的字符串操作中解放出来,专注于业务逻辑本身。
